热门搜索样式布局
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;
`
...
效果是,输入框获得焦点,显示下面的框框;失去焦点的时候,框框消失。

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"></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'}></span>
{this.getListArea()}
</SearchWrapper>
<Addition>
<Button className='writting'>
<span className="iconfont"></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)

网友评论