登陆页面布局
这节,我们来做登录页面的布局
1.先写登录页面的路由
//===>src/App.js
import React from 'react';
import Header from './common/header'
import store from './store'
import { Provider } from 'react-redux'
import { BrowserRouter, Route } from 'react-router-dom'
import Home from './pages/home';
import Detail from './pages/detail'
import Login from './pages/login'
function App() {
return (
);
}
export default App;
2.Login组件布局
//===>src/pages/login/index.js
import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import { LoginWrapper, LoginBox, Input, Buttom } from './style'
class Login extends PureComponent {
render() {
return (
登录
)
}
}
const mapState = (state) => ({
})
const mapDispatch = (dispatch) => ({
})
export default connect(mapState, mapDispatch)(Login)
3.编写布局样式
//===>src/pages/login/style.js
import styled from 'styled-components'
export const LoginWrapper = styled.div`
z-index:0;
position:absolute;
left:0;
right:0;
bottom:0;
top:56px;
background:#eee;
`
export const LoginBox = styled.div`
width:400px;
height:180px;
margin:100px auto;
padding-top:20px;
background:#fff;
box-shadow:0 0 8px rgba(0,0,0,.1);
`
export const Input = styled.input`
display:block;
width:200px;
height:30px;
line-height:30px;
padding:0 10px;
margin:10px auto;
color:#777;
`
export const Buttom = styled.div`
width:220px;
height:30px;
line-height:30px;
color:#fff;
background:#3194d0;
border-radius:15px;
margin:10px auto;
text-align:center;
`
我们注意到在LoginWrapper的样式中,我们加入了z-index:0;他的作用是把Login页面置于Header底层,否则不能显示出Header中Search组件的框框了。所以我们还要在Header组件的style文件中,提高Search的z-index
//===>src/common/header/style.js
...
export const HeaderWrapper = styled.div`
z-index:1;
position:relative;
height:56px;
border-bottom:1px solid #f0f0f0;
`
...
登陆功能实现
我们要实现登录登出功能。表现方式是:未登录状态,Header组件右边显示登陆;已登录状态,Header组件右边显示退出。未登录时候,跑/login地址,填表后,点击登录登陆状态改变,并跳转至首页。
1.先写一个登录模拟接口
//===>public/api/login.json
{
"success": true,
"data": true
}
2.我们写登录相关常量
//===>src/pages/login/store/constants.js
export const CHANGE_LOGIN = 'login/CHANGE_LOGIN'
export const CHANGE_LOGOUT = 'login/CHANGE_LOGOUT'
3.然后要写actionCreators
//===>src/pages/login/store/actionCreators.js
import axios from 'axios'
import * as constants from './constants'
const changeLogin = () => ({
type: constants.CHANGE_LOGIN,
value: true
})
export const logout = () => ({
type: constants.CHANGE_LOGOUT,
value: false
})
export const login = (account, password) => {
return (dispatch) => {
axios.get('/api/login.json?account=' + account + '&password' + password)
.then((res) => {
const result = res.data.data
if (result) {
dispatch(changeLogin())
} else {
alert('登陆失败')
}
})
}
}
4.reducer
//===>src/pages/login/store/reducer.js
import { fromJS } from 'immutable'
import * as constants from './constants'
const defaultState = fromJS({
login: false
})
export default (state = defaultState, action) => {
switch (action.type) {
case constants.CHANGE_LOGIN:
return state.set('login', action.value)
case constants.CHANGE_LOGOUT:
return state.set('login', action.value)
default:
return state
}
}
5.login的reducer写好了,我们还要把他注册到全局reducer中
//===>src/store/reducer.js
import { combineReducers } from 'redux-immutable'
import { reducer as headerReducer } from '../common/header/store'
import { reducer as homeReducer } from '../pages/home/store'
import { reducer as detailReducer } from '../pages/detail/store'
import { reducer as loginReducer } from '../pages/login/store'
const reducer = combineReducers({
header: headerReducer,
home: homeReducer,
detail: detailReducer,
login: loginReducer
})
export default reducer
6.我们把这些东西暴露出来
//===>src/pages/login/store/index.js
import reducer from './reducer'
import * as actionCreators from './actionCreators'
import * as constants from './constants'
export { reducer, actionCreators, constants }
7.接下来是header组件和login页面逻辑
//===>src/common/header/index.js
import React, { Component, Fragment } from 'react'
import { CSSTransition } from 'react-transition-group'
import {
HeaderWrapper,
Logo,
Nav,
NavItem,
SearchWrapper,
NavSearch,
SearchInfo,
SearchInfoTitle,
SearchInfoSwitch,
SearchInfoList,
SearchInfoItem,
Addition,
Button
} from './style'
import { IconFontStyle } from '../../statics/iconfont/iconfont';
import { connect } from 'react-redux';
import { actionCreators } from './store';
import { Link } from 'react-router-dom'
import { actionCreators as loginActionCreators } from '../../pages/login/store'
class Header extends Component {
getListArea() {
const { focused, list, page, totalPage, mouseIn, handleMouseEnter, handleMouseLeave, handleChangePage } = this.props
const newList = list.toJS()
const pageList = []
if (newList.length) {
for (let i = ((page - 1) * 10); i < page * 10; i++) {
pageList.push(
{newList[i]}
)
}
}
if (focused || mouseIn) {
return (
热门搜索
handleChangePage(page, totalPage, this.spinIcon)}>
{ this.spinIcon = icon }} className="iconfont spin">换一批
{pageList}
)
} else {
return null;
}
}
render() {
const { focused, handleInputFocus, handleInputBlur, list, login, logout } = this.props
return (
)
}
}
const mapStateToProps = (state) => {
return {
// focused: state.get('header').get('focused')
focused: state.getIn(['header', 'focused']),
list: state.getIn(['header', 'list']),
page: state.getIn(['header', 'page']),
totalPage: state.getIn(['header', 'totalPage']),
mouseIn: state.getIn(['header', 'mouseIn']),
login: state.getIn(['login', 'login'])
}
}
const mapDispatchToProps = (dispatch) => {
return {
handleInputFocus(list) {
if (list.size === 0) {
dispatch(actionCreators.getList())
}
dispatch(actionCreators.searchFocus())
},
handleInputBlur() {
dispatch(actionCreators.searchBlur())
},
handleMouseEnter() {
dispatch(actionCreators.mouseEnter())
},
handleMouseLeave() {
dispatch(actionCreators.mouseLeave())
},
handleChangePage(page, totalPage, spin) {
let originAngle = spin.style.transform.replace(/[^0-9]/ig, '')
if (originAngle) {
originAngle = parseInt(originAngle, 10)
} else {
originAngle = 0
}
spin.style.transform = 'rotate(' + (originAngle + 360) + 'deg)'
if (page < totalPage) {
dispatch(actionCreators.changePage(page + 1))
} else {
dispatch(actionCreators.changePage(1))
}
},
logout() {
dispatch(loginActionCreators.logout())
}
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Header)
//===>src/pages/login/index.js
import React, { PureComponent } from 'react'
import { connect } from 'react-redux'
import { LoginWrapper, LoginBox, Input, Buttom } from './style'
import { actionCreators } from './store'
import { Redirect } from 'react-router-dom'
class Login extends PureComponent {
render() {
const { loginStatus } = this.props;
if (!loginStatus) {
return (
{ this.account = input }} />
{ this.password = input }} />
this.props.login(this.account, this.password)}>登录
)
} else {
return
}
}
}
const mapState = (state) => ({
loginStatus: state.getIn(['login', 'login'])
})
const mapDispatch = (dispatch) => ({
login(accountElem, passwordElem) {
dispatch(actionCreators.login(accountElem.value, passwordElem.value))
}
})
export default connect(mapState, mapDispatch)(Login)