美文网首页
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