美文网首页
12.项目实战:Header组件开发(四)

12.项目实战:Header组件开发(四)

作者: 小二的学习日记 | 来源:发表于2020-07-20 11:33 被阅读0次

    热门搜索样式布局

    1.编写组件结构

    //===>src/common/header/index.js
    import {
        HeaderWrapper,
        Logo,
        Nav,
        NavItem,
        SearchWrapper,
        NavSearch,
        SearchInfo,
        SearchInfoTitle,
        SearchInfoSwitch,
        SearchInfoList,
        SearchInfoItem,
        Addition,
        Button
    } from './style'
    ...
    const getListArea = (show) => {
        if (show) {
            return (
                <SearchInfo>
                    <SearchInfoTitle>
                        热门搜索
                                    <SearchInfoSwitch>换一批</SearchInfoSwitch>
                    </SearchInfoTitle>
                    <SearchInfoList>
                        <SearchInfoItem>教育</SearchInfoItem>
                        <SearchInfoItem>教育</SearchInfoItem>
                        <SearchInfoItem>教育</SearchInfoItem>
                        <SearchInfoItem>教育</SearchInfoItem>
                        <SearchInfoItem>教育</SearchInfoItem>
                        <SearchInfoItem>教育</SearchInfoItem>
                    </SearchInfoList>
                </SearchInfo>
            )
        } else {
            return null;
        }
    }
    const Header = (props) => {
        return (
          ...
           <SearchWrapper>
                ...
                {getListArea(props.focused)}
           </SearchWrapper>
          ...
        )
    }
    

    2.根据styled-components三方组件库,编写第一部定义的结构中的样式

    //===>src/common/header/style.js
    ...
    export const SearchInfo = styled.div`
    position:absolute;
    left:0;
    top:56px;
    width:240px;
    padding:0 20px;
    box-shadow:0 0 8px rgba(0,0,0,.2);
    `
    
    export const SearchInfoTitle = styled.div`
    margin-top:20px;
    margin-bottom:15px;
    line-height:20px;
    font-size:14px;
    color:#969696;
    `
    export const SearchInfoSwitch = styled.span`
    float:right;
    font-size:13px;
    `
    export const SearchInfoList = styled.div`
    overflow:hidden;
    `
    
    export const SearchInfoItem = styled.a`
    display:block;
    float:left;
    line-height:20px;
    padding:0 5px;
    margin-right:10px;
    margin-bottom:15px;
    font-size:12px;
    border:1px solid #ddd;
    color:#787878;
    border-radius:3px;
    `
    ...
    

    效果是,输入框获得焦点,显示下面的框框;失去焦点的时候,框框消失。

    image.png

    Ajax获取推荐数据

    这一小节,我们的目标是,实现热门搜索数据的调取。
    1.首先我们来安装axios和thunk两个三方库
    cnpm install --save axios
    cnpm install --save thunk
    2.我们来做模拟接口
    在react项目中,我们可以在public文件夹中创建模拟接口
    新建src/public/api/headerList.json

    //===>src/public/api/headerList.json
    {
        "success":true,
        "data":["模拟1","模拟2","模拟3","模拟4","模拟5","模拟6","模拟7","模拟8","模拟9","模拟10"]
    }
    

    这样,我们在项目中请求/api/headerList.json这个地址,就可以访问到它里面的数据了。
    3.thunk是redux异步请求的中间件,我们要把它注册到store中

    //===>src/store/index.js
    import { createStore, compose, applyMiddleware } from 'redux'
    import reducer from './reducer'
    import thunk from 'redux-thunk'
    
    const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
    const store = createStore(reducer, composeEnhancers(
        applyMiddleware(thunk)
    ));
    export default store
    

    4.新建action关于这次请求数据的type常量

    //===>src/common/header/store/constants.js
    ...
    export const CHANGE_LIST = 'header/CHANGE_LIST'
    

    5.编写actionCreators,获取异步数据
    这里我们用fromJS包装data,是因为我们用了immutable去保护state,在Header组件中获取数据的时候接收的,也应该是immutable数据。所以在这里创建好immutable数据返回给reducer就方便了。

    //===>src/common/header/store/actionCreators.js
    import *  as constants from './constants'
    import axios from 'axios'
    import { fromJS } from 'immutable'
    ...
    const changeList = (data) => ({
        type: constants.CHANGE_LIST,
        data: fromJS(data)
    })
    
    export const getList = () => {
        return (dispatch) => {
            axios.get('/api/headerList.json').then((res) => {
                const data = res.data.data;
                const action = changeList(data)
                dispatch(action)
            }).catch(() => {
                console.log('err');
            })
        }
    }
    

    6.action有了,接下来要用reducer去调用了

    //===>src/common/header/store/reducer.js
    import *  as constants from './constants'
    import { fromJS } from 'immutable'
    
    const defaultState = fromJS({
        focused: false,
        list: []
    })
    
    export default (state = defaultState, action) => {
    
        switch (action.type) {
            case constants.SEARCH_FOCUS:
                return state.set('focused', true)
            case constants.SEARCH_BLUR:
                return state.set('focused', false)
            case constants.CHANGE_LIST:
                return state.set('list', action.data)
            default:
                return state
        }
    }
    

    7.最后,我们在Header写下搜索数据部分的逻辑。(我把Header组件的代码全部贴上,因为我们改了结构,把函数式的改成了一个组件类,这样方便一点。)

    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';
    
    class Header extends Component {
    
        getListArea() {
            const { focused, list } = this.props
            if (focused) {
                return (
                    <SearchInfo>
                        <SearchInfoTitle>
                            热门搜索
                                        <SearchInfoSwitch>换一批</SearchInfoSwitch>
                        </SearchInfoTitle>
                        <SearchInfoList>
                            {
                                list.map((item) => {
                                    return <SearchInfoItem key={item}>{item}</SearchInfoItem>
                                })
                            }
                        </SearchInfoList>
                    </SearchInfo>
                )
            } else {
                return null;
            }
        }
    
        render() {
            const { focused, handleInputFocus, handleInputBlur } = this.props
            return (
                <Fragment>
                    <IconFontStyle />
                    <HeaderWrapper>
                        <Logo />
                        <Nav>
                            <NavItem className='left'>首页</NavItem>
                            <NavItem className='left'>下载App</NavItem>
                            <NavItem className='right'>登录</NavItem>
                            <NavItem className='right'>
                                <span className="iconfont">&#xe636;</span>
                            </NavItem>
                            <SearchWrapper>
                                <CSSTransition
                                    in={focused}
                                    timeout={200}
                                    classNames="slide">
                                    <NavSearch
                                        className={focused ? 'focused' : ''}
                                        onFocus={handleInputFocus}
                                        onBlur={handleInputBlur}>
                                    </NavSearch>
                                </CSSTransition>
                                <span className={focused ? 'focused iconfont' : 'iconfont'}>&#xe662;</span>
                                {this.getListArea()}
                            </SearchWrapper>
                            <Addition>
                                <Button className='writting'>
                                    <span className="iconfont">&#xe6e5;</span>写文章
                                </Button>
                                <Button className='reg'>注册</Button>
                            </Addition>
                        </Nav>
                    </HeaderWrapper>
                </Fragment>
            )
        }
    }
    
    const mapStateToProps = (state) => {
        return {
            // focused: state.get('header').get('focused')
            focused: state.getIn(['header', 'focused']),
            list: state.getIn(['header', 'list'])
        }
    }
    
    const mapDispatchToProps = (dispatch) => {
        return {
            handleInputFocus() {
                dispatch(actionCreators.getList())
                dispatch(actionCreators.searchFocus())
            },
            handleInputBlur() {
                dispatch(actionCreators.searchBlur())
            }
        }
    }
    
    export default connect(mapStateToProps, mapDispatchToProps)(Header)
    
    效果

    相关文章

      网友评论

          本文标题:12.项目实战:Header组件开发(四)

          本文链接:https://www.haomeiwen.com/subject/hdulkktx.html