功能:换一换
之前我们让数据全部显示出来 但现在我需要只显示一部分
小reducer.js
import * as constants from './constants';
import { fromJS } from 'immutable';
const defaultState =fromJS({
focused:false
list:[],
page:0,//当前页
totalPage:1,//全部页
mouseIn:false //是否进入了热门搜索区块
});
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)
.set('totalPage',action.totalPage);
case constants.MOUSE_ENTER:
return state.set('mouseIn',true);
case constants.MOUSE_LEAVE:
return state.set('mouseIn',false);
case constants.CHANGE_PAGE:
return state.set('page',action.page);
default:
return state;
}
}
然后我们需要对全部页码进行改变
actionCreators.js
import * as constants from './constants';
import axios from 'axios';
import {fromJS} from 'immutable';
export const searchFocus =()=> ({
type:constants.SEARCH_FOCUS;
})
export const searchBlur =()=> ({
type:constants.SEARCH_BLUR;
})
export const mouseEnter =()=> ({
type:constants.MOUSE_ENTER; //constants里同时建立
});
export const mouseLeave =()=> ({
type:constants.MOUSE_LEAVE; //constants里同时建立
});
export const changePage =(page)=> ({
type:constants.CHANGE_PAGE; //constants里同时建立
page
});
const changeList =(data) =>({//所以要把Data变成immutable数组
type:constants.CHANGE_LIST,
data:fromJS(data),
totalPage:Math.ceil(data.length / 10 ) //Math.ceil() === 向上取整
});
export const getList = () => {
return (dispatch) => {
axios.get('/api/headerList.json').then((res) =>{
const data=res.data;
dispatch(changeList(data.data));
}).catch(()=>{
console.log('error');
})
}
};
之后我们需要将第一页显示出来
header/index.js
//我们向login里面的store派发 要引入
import { actionCreators as loginActionCreators } from '../../pages/login/store';
class Header extends Component {
getListArea () {
//简化 即可删掉this.props
const { focused,list,page }=this.props;
const newList = list.toJS();//转化成普通数组
const pageList = [];
if(newList.length){//有值才循环
//加一个循环 初始为第0条到第9条
for(let i =(page * 10);i< (page+1)*10 ; i++){
pageList.push(
<SearchInfoItem key={newList[i]}> {newList[i]} </SearchInfoItem>
)
}
}
if(mouseIn || focused){ //只要一个在就要显示这个区块
return (
//onmouseenter 事件在鼠标指针移动到元素上时触发
<SearchInfo
onMouseEnter = {this.props.handleMouseEnter}
onMouseLeave = {this.props.handleMouseLeave}
>
<SearchInfoTitle>
热门搜索
<SearchInfoSwitch onClick={() => handleChangePage(page,totalPage)}>
换一批
</SearchInfoSwitch>//同时传递过去页码、总页码
</SearchInfoTitle>
<SearchInfoList>
{
{pageList}
})
}
</SearchInfoList>
</SearchInfo>) }
else
{return null;}
}
render(){
const { login,logout } =this.props;
return (
<HeaderWrapper>
<Logo href='/' />
<Nav>
<NavItem className='left active'>首页</NavItem>
<NavItem className='left'>下载App</NavItem>
{
login?<NavItem onClick={logout} className='right'>退出</NavItem>:
<link to='/login'><NavItem className='right'>登陆</NavItem></link>
}
<NavItem className='right'>Aa</NavItem>
<SearchWrapper>
<CSSTransition
in={this.props.focused} //根据哪个值
timeout={200}//时长
classNames="slide">//名字
<NavSearch>
className={this.props.focused ? 'focused':' '}
onFocus={this.props.handleInputFocus}
onBlur={this.props.handleInputBlur}//离开聚焦时
</NavSearch>
</CSSTransition>
<i className={this.props.focusd?'focused iconfont':' '}>

</i>
{this.getListArea()}//调用方法
</SearchWrapper>
</Nav>
<Addition>
<Button className='reg'>注册</Button>
<Button className='writting'> 写文章</Button>
</Addition>
</HeaderWrapper>
)
}
const mapStateToProps =( state )=> {//store里数据state如何映射到props
return {
focused:state.getIn('header','focused']),
list:state.getIn('header','list']),
page:state.getIn('header','page']),//拿到页码了
mouseIn:state.getIn('header','mouseIn']),
totalPage:state.getIn('header','totalPage']),
login:state.getIn('login','login'])
}
}
const mapDispatchToProps =( dispatch )=> {//组件改变store里数据
return {
handleInputFocus(){
dispatch(actionCreators.getList());
dispatch(actionCreators.searchFocus());//action由actioncreators创建
},
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,'');
//如果里面的不是0-9数字则替换为空
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);
我们还发现 热门搜索这一块不是由focuse 聚焦input框实现的
注意发送换一换功能的action时同时还要发送总页码和当前页的相关变量
然后我们来解决key值问题:
在页面渲染时我们代码中key={…}的那个循环也会开始,所以代码中很多变量都是undefined,所以才会出WARNING警告,所以我们要进行判断。
代码优化:
.set是我们改变store的immutable数据的一种方法,但如果需要同时改变很多值,我们不能set很多串,采用另一种方法merge
即
return state.merge({
list:action.data,
totalPage:action.totalPage
});
换一换图标动画效果
先在iconfont中找一个spin
运行之后发现该图标在右下角
因为之前搜索图标已经修改了它的位置靠右下
index.js
之前那个搜索的图标:
<i className={this.props.focusd?'focused iconfont zoom':'iconfont zoom '}>

</i>//末尾加上‘ zoom’
新加的换一换图标:
<SearchInfoTitle>
热门搜索
<SearchInfoSwitch onClick={() => handleChangePage(page,totalPage,this.spinIcon)}>
//ref可以获取到dom节点,并且可以进一步获得它的css样式
<i ref={(icon)=>{this.spinIcon = icon}} className="iconfont spin"></i>
换一批
</SearchInfoSwitch>//同时传递过去页码、总页码
</SearchInfoTitle>
style.js
export const SearchWrapper = styled.div`
float:left;
position:relative;
.zoom {//修改成zoom
position :absolute;
right:5px;
bottom:5px;
width:30px;
line-height:30px;
border-radius:15px;
text-align:center;
}
`
我们开始加动画效果
export const searchInfoSwitch = styled.span`
...其他略
.spin{
display:block;//只有block才能进行旋转rotate
float:left;
font-size:12px;
margin-right:2px;
transition:all .2s easy-in;//两秒内完成动画
transform:rotate(0deg);//旋转
transform-origin:center center;//以中心点旋转 x y 轴
}
`;
其他地方修改详见上面代码
代码优化之避免无意义的请求发送,提高性能:
我们发现热门搜索这一栏无需点一次请求一次,只需请求一次就足够了
<NavSearch>
className={this.props.focused ? 'focused':' '}
onFocus={() => this.props.handleInputFocus(list)}
//把list传进来
</NavSearch>
handleInputFocus(){
if(list.size===0){
dispatch(actionCreators.getList());
}
dispatch(actionCreators.searchFocus());//action由actioncreators创建
},
简洁写法:
handleInputFocus(){
(list.size===0)&&dispatch(actionCreators.getList());
dispatch(actionCreators.searchFocus());//action由actioncreators创建
},
附加:改变鼠标指针样式
我希望在鼠标移到换一批时指针变为手型
找到SearchInfoSwitch
cursor:pointer
我们需要让未登陆时显示“登陆”,登陆后显示”退出“
在mapstatetoprops里建login