首先上效果图:

React 登录和后台session react 登陆界面_Boo

选择皮肤下拉。

React 登录和后台session react 登陆界面_Boo_02

功能分析:

  • 点击记住用户名区域,checkbox选中,再点击则checkbox取消选中。
  • 点击皮肤选择框,会显示皮肤下拉。
  • 如果记住用户勾选了,则从本地缓存中读取上次登陆的用户名称。
  • 如果记住用户勾选了,则点击登陆提交时,需要将当前用户的名称保存到本地缓存中。
  • 点击皮肤选择框,弹出皮肤选择下拉,但点击界面其他地方时将下拉框隐藏。
  • 点击登陆按钮时请求后台数据,如果登陆成功跳转界面。
  • 如果登陆失败则弹出错误提醒框。

代码存放位置:

React 登录和后台session react 登陆界面_react_03

直接上代码了:
Login.js的内容:

import React, { Component } from 'react' // 引入React
import { connect,dispatch } from 'react-redux' // 引入connect

import topTitleLog from './images/topTitleLog.png';
import sysLogo from './images/sysLogo.png';
import paopao from './images/paopao.png';

import SkinDropCom from '../../components/SkinDropCom';
import 'antd/dist/antd.css';  // or 'antd/dist/antd.less'
import '../../assets/css/goingStyle.css';
import './Login.less';
import 'font-awesome/css/font-awesome.min.css';
import {parseBoolean,AssertUtils} from '../../utils/GoingUtils';
import { Link } from 'react-router'
import {  notification } from 'antd';


class Login extends Component {
  //构造函数 绑定事件
  constructor(...props) {
    super(...props);
    [
      '_setCurUserName', '_clickLoginBtn', '_selCheckBoxEl', '_setPsw', '_changeCurSkin','_showDropDown'
    ].forEach(func=> {
      this[func] = this[func].bind(this);
    });
  }

  componentWillMount() {
  }

  //如果挑战界面 存在错误信息  将错误内容展示出来
  componentDidUpdate() {
    const { dispatch,loginMd}=this.props;
    if (loginMd.error != null) {
      notification['error']({
        message: '错误信息',
        description: `系统登陆失败,失败原因:${loginMd.error}`,
      });

    }
  }

  //校验用户名 跟 密码是否为空
  validateFieldsAndScroll({userName,password}) {
    if (AssertUtils.isNotEmpty(userName) && AssertUtils.isNotEmpty(password)) {
      return true;
    } else {
      notification['error']({
        message: '错误信息',
        description: `用户名或者密码信息不能为空,请确认!`,
      });
      return false;
    }
  }

  //点击登陆按钮 跳转到首页
  _clickLoginBtn() {
    const { dispatch,loginMd}=this.props;
    if (this.validateFieldsAndScroll(loginMd)) {
      //如果是需要记录当前用户名 则将当前用户名称记录到本地缓存中
      if (parseBoolean(loginMd.checkVal)) {
        let newUserName = loginMd.userName;
        localStorage.removeItem("userName");
        localStorage.setItem("userName", newUserName);
      }
      dispatch({
        type: 'loginMd/loginSys'
      });
    }
  }

  //点击记住用户名的checkbox
  _changeCurSkin(selSkin) {
    const { dispatch,loginMd}=this.props;
    dispatch({
      type: 'loginMd/changeCurSkin',
      curSkin: selSkin
    });
  }

  //点击记住用户名的checkbox
  _selCheckBoxEl() {
    const { dispatch,loginMd}=this.props;
    dispatch({
      type: 'loginMd/selCheckBox',
      checkVal: loginMd.checkVal
    });
  }
  //显示皮肤选择下拉
  _showDropDown(visibilityFlag){
    const { dispatch,loginMd}=this.props;
    dispatch({
      type: 'loginMd/showDropDown',
      visibilityFlag: visibilityFlag
    });
  }
  //变更密码时 将值放入到状态里管理起来
  _setPsw(ev) {
    const { dispatch,loginMd}=this.props;
    var newPwd = ev.target.value;
    dispatch({
      type: 'loginMd/changePwd',
      password: newPwd
    });
  }

  //变更用户时 将值放入到状态里管理起来
  _setCurUserName(ev) {
    const { dispatch,loginMd}=this.props;
    var newUserName = ev.target.value;
    dispatch({
      type: 'loginMd/changeUserName',
      userName: newUserName
    });
  }

  render() {
    const {loginMd} =this.props;
    let userName = loginMd.userName;
    console.log(this.props.location+"-----------------")
    if (parseBoolean(loginMd.loginHome)) {
      window.location.href = "http://localhost:8000/";
    }
    return (
      <div>
        <header>
          <div className="loginSysImg">
            <img src={topTitleLog}/>
          </div>
          <div className="loginSysTitle">
            <span>欢迎访问ERP系统</span>
          </div>
        </header>
        <div className="pageBody">
          <div className="sysImgDiv">
            <img src={sysLogo}/>
          </div>
          <div className="loginWin">
            <div className="goingFlexRow">
              <div><input type="text" ref="userName" value={userName} onChange={this._setCurUserName}/></div>
              <div className="inputImg"><i className="fa fa-user" aria-hidden="true"></i></div>
            </div>
            <div className="goingFlexRow">
              <div><input type="password" onChange={this._setPsw}/></div>
              <div className="inputImg"><i className="fa fa-key" aria-hidden="true"></i></div>
            </div>
            <div className="goingFlexRow" onClick={(ev)=>{
                   this._showDropDown(true);
                   ev.stopPropagation();
              }}>
              <div>
                <input type="text" value={loginMd.currentSkin} onChange={()=>{}}/>
              </div>
              <div className="inputImg"><i className="fa fa-caret-down" aria-hidden="true"></i></div>
            </div>

            <SkinDropCom skinsList={loginMd.skinsList} visibility={loginMd.visibility}
                         changeCurSkin={this._changeCurSkin} showDropDown={this._showDropDown} width="180px"/>

            <div className="goingButtonRow">
              <div className="labelInfo" onClick={()=>this._selCheckBoxEl()}>
                <span><input type="checkbox" checked={parseBoolean(loginMd.checkVal)} onChange={()=>{}}/></span>
                <span><label>记住用户名</label></span>
              </div>
              <div className="loginBtnDiv">
                <button onClick={()=>this._clickLoginBtn()}>登陆</button>
              </div>
            </div>
          </div>
        </div>

        <footer>
          <div className="sysRight">@copy Right 科技公司版权所有</div>
        </footer>
      </div>
    )
  }
}


// 利用connect将组件与Redux绑定起来
export default connect(({loginMd}) => ({loginMd}))(Login)

login.less文件内容:

@startCol: #FAFAFA;
@endCol: #F0F0F0;
@navHeight:30px;@baseBorderCol:#CCCCCC;

header,footer{
  height: @navHeight;
  width: 100%;
  background: linear-gradient(@startCol, @endCol); /* 标准的语法 */
  display: flex;
}
header {
  div.loginSysImg {
    margin-left: 10px;
  }
  div.loginSysTitle {
    margin-left: 10px;
    line-height: @navHeight;
    font-size: 13px;
    color: #494949;
  }
}

div.pageBody {
  position: absolute;
  width: 100%;
  top: 33%;
  height: 150px;
  background: linear-gradient(#76CBD4, #2D93A1); /* 标准的语法 */
  display: flex;
  justify-content: center;
  div.sysImgDiv {
    position: relative;
    top: -48px;
    left: -10px;
  }
  div.loginWin {
    padding: 10px 10px;
    width: 200px;
    div.goingFlexRow {
      width: 100%;
      margin-top: 6px;
      display: flex;
    }
    div.goingButtonRow {
      display: flex;
      justify-content: space-between;
      margin-top: 10px;
      .labelInfo {
        position: relative;
        top: 5px;
        label {
          position: relative;
          top: -3px;
          left: 5px;
          color: #fff;
          display: inline-block;
        }
      }
      .loginBtnDiv {
        cursor: pointer;
        position: relative;
        button {
          width: 70px;
          height: 25px;
          line-height: 25px;
          cursor: pointer;
          &:hover {
            background: linear-gradient(#DDDDDD, #C9C9C9); /* 标准的语法 */
          }
        }

      }
    }
  }
}

footer {
  position: fixed;
  bottom: 0px;
  border-top: 1px solid @baseBorderCol;
  .sysRight {
    line-height:@navHeight;
    margin-left: 10px;
    font-size: 13px;
  }

}

.inputImg {
  position: relative;
  left: -16px;
  top: 3px;
}

.inputCom{
  height: 23px;
  width: 180px;
  border: 1px solid @baseBorderCol;
  border-radius: 3px;
}
input[type="text"] {
  .inputCom;
}

input[type="password"] {
  .inputCom;
}

input[type="checkbox"] {
  height: 15px;
  width: 15px;
}

dva对redux封装了,所以使用起来不需要单独去写所谓的action,以及reducer相关文件。

Login.js直接关联到了src/models/LoginMd.js.
如何关联的:第一步就是新建一个LoginMd.js,并将该models注册到index.js里面

app.model(require('./models/LoginMd'));

第二步,在Login.js文件开发时,将该文件对应的对象映射进来:

// 利用connect将组件与Redux绑定起来
export default connect(({loginMd}) => ({loginMd}))(Login)

这样就完成了redux相关的各种配置了,确实要简单多了。

src/models/LoginMd.js的内容如下

import {loginSv, findCurrentUser, logout} from '../services/LoginSv'
import {parse} from 'qs'
import {parseBoolean,AssertUtils} from '../utils/GoingUtils';

export default {
  namespace: 'loginMd',
  state: {
    //从本地缓存中读取是否选中的状态值
    checkVal:((curCheckVal=false)=>{
      return curCheckVal;
    })(localStorage.getItem("checkVal")),
    userName:(()=>{
      //如果记住用户名是true 则本地缓存中获取用户信息
      if(parseBoolean(localStorage.getItem("checkVal"))){
        return localStorage.getItem("userName");
      }else{
        return '';
      }
    })(),
    visibility:"hidden",
    currentSkin:((currentSkin='蓝色金典')=>{
      return currentSkin;
    })(localStorage.getItem("currentSkin")||'蓝色金典'),
    //皮肤下拉
    skinsList: [
      {text: '蓝色金典',itemId:'blue'},
      {text: '浅色简约',itemId:'apply'},
      {text: '简约时尚',itemId:'shisha'}
    ]
  },
  subscriptions: {
    setup({ dispatch, history }) {  // eslint-disable-line
    },
  },
  effects: {
    *loginSys({ payload }, { call, put }) {
      const record = yield call(loginSv, parse(payload));
      if (record.code) {
        yield put({
          type: 'loginSuccess',
          payload: {
            user: record.data
          }})
      } else {
        yield put({
          type: 'loginFail'
        })
      }
    },
  },
  reducers: {
    selCheckBox(state, action) {
      //讲checkVal的值保存到本地缓存中
      localStorage.removeItem("checkVal");
      localStorage.setItem("checkVal",!parseBoolean(action.checkVal));
      return { ...state, checkVal:!parseBoolean(action.checkVal)};
    },
    changeUserName(state, action) {
      //用户名输入的值变更
      return { ...state, userName:action.userName};
    },
    changePwd(state, action) {
      //密码值的变更
      return { ...state, password:action.password};
    },
    showDropDown(state, action) { 
      //皮肤下拉的显示与隐藏
      return { ...state, visibility:parseBoolean(action.visibilityFlag)?"visible":"hidden"};
    },
    changeCurSkin(state, action) {
      //选择相应的皮肤选项
      localStorage.removeItem("currentSkin");
      localStorage.setItem("currentSkin",action.curSkin);
      return { ...state, visibility:"hidden",currentSkin:action.curSkin};
    },
    loginSuccess (state, action) { 
      //登陆成功
      return {
        ...state,
        ...action.payload,
        loginHome: true,
        loginButtonLoading: false
      }
    },
    loginFail (state) {
      return {
        ...state,
        login: false,
        error:'用户名或者密码不正确',
        loginButtonLoading: false
      }
    },
  },
};

调用原理:
当在Login.js文件中调用:

dispatch({
      type: 'loginMd/changePwd',
      password: newPwd
    });

loginMd/changePwd中的loginMd对应的是Models的命名空间

namespace: 'loginMd',

loginMd/changePwd中的changePwd对应reducers下的相应方法

changePwd(state, action) {
      //密码值的变更
      return { ...state, password:action.password};
    },

到此就完成了登陆界面的开发。该界面里面用到了一个封装组件,皮肤下拉,下节我们来介绍该组件的实现。