首先上效果圖:

選擇皮膚下拉。
功能分析:
- 點選記住使用者名區域,checkbox選中,再點選則checkbox取消選中。
- 點選皮膚選擇框,會顯示皮膚下拉。
- 如果記住使用者勾選了,則從本地緩存中讀取上次登陸的使用者名稱。
- 如果記住使用者勾選了,則點選登陸送出時,需要将目前使用者的名稱儲存到本地緩存中。
- 點選皮膚選擇框,彈出皮膚選擇下拉,但點選界面其他地方時将下拉框隐藏。
- 點選登陸按鈕時請求背景資料,如果登陸成功跳轉界面。
- 如果登陸失敗則彈出錯誤提醒框。
代碼存放位置:
直接上代碼了:
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:px;@baseBorderCol:#CCCCCC;
header,footer{
height: @navHeight;
width: %;
background: linear-gradient(@startCol, @endCol); /* 标準的文法 */
display: flex;
}
header {
div.loginSysImg {
margin-left: px;
}
div.loginSysTitle {
margin-left: px;
line-height: @navHeight;
font-size: px;
color: #494949;
}
}
div.pageBody {
position: absolute;
width: %;
top: %;
height: px;
background: linear-gradient(#76CBD4, #2D93A1); /* 标準的文法 */
display: flex;
justify-content: center;
div.sysImgDiv {
position: relative;
top: -px;
left: -px;
}
div.loginWin {
padding: px px;
width: px;
div.goingFlexRow {
width: %;
margin-top: px;
display: flex;
}
div.goingButtonRow {
display: flex;
justify-content: space-between;
margin-top: px;
.labelInfo {
position: relative;
top: px;
label {
position: relative;
top: -px;
left: px;
color: #fff;
display: inline-block;
}
}
.loginBtnDiv {
cursor: pointer;
position: relative;
button {
width: px;
height: px;
line-height: px;
cursor: pointer;
&:hover {
background: linear-gradient(#DDDDDD, #C9C9C9); /* 标準的文法 */
}
}
}
}
}
}
footer {
position: fixed;
bottom: px;
border-top: px solid @baseBorderCol;
.sysRight {
line-height:@navHeight;
margin-left: px;
font-size: px;
}
}
.inputImg {
position: relative;
left: -px;
top: px;
}
.inputCom{
height: px;
width: px;
border: px solid @baseBorderCol;
border-radius: px;
}
input[type="text"] {
.inputCom;
}
input[type="password"] {
.inputCom;
}
input[type="checkbox"] {
height: px;
width: px;
}
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的命名空間
loginMd/changePwd中的changePwd對應reducers下的相應方法
changePwd(state, action) {
//密碼值的變更
return { ...state, password:action.password};
},
到此就完成了登陸界面的開發。該界面裡面用到了一個封裝元件,皮膚下拉,下節我們來介紹該元件的實作。
具體細節不講了,有興趣的可以q我,一起探讨學習