22 项目实战:详情页面和登录功能开发(三)

登陆页面布局

这节,我们来做登录页面的布局
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)
image.png

你可能感兴趣的:(22 项目实战:详情页面和登录功能开发(三))