热门搜索换页功能实现

我们热门搜索,有一个“换一批”的按钮,点击它,就会换一批热门关键字。

我们的实现是,ajax 获取很多热门搜索关键字,但只会显示十个,点击换一批会显示下一批十个关键字。

那我们再去src/common/header/store 下的reducer.js 中新增两个数据page(当前页)、totalPage(总页数),如下。

import { SEARCH_FOCUS, SEARCH_BLUR, CHANGE_LIST } from './actionTypes';
import { fromJS } from 'immutable';

const defaultState = fromJS({
    focused: false,
    list: [],
    page: 1,
    totalPage: 1
});

export default (state = defaultState, action) => {
    switch (action.type) {
        case SEARCH_FOCUS :
            return state.set("focused", true);
        case SEARCH_BLUR:
            return state.set("focused", false);
        case CHANGE_LIST:
            return state.set("list", action.data);
        default:
            return state;
    }
}

那我们在返回数据的时候,要修改一下totalPage 的值。因此,我们打开src/common/header/store 下的 actionCreators.js 文件。修改其中的 changeList 方法,如下。

import * as actionTypes from './actionTypes';
import axios from 'axios';
import { fromJS } from 'immutable';
import '../../../mockdata.js';

const changeList = (data) => ({
  type: actionTypes.CHANGE_LIST,
  data: fromJS(data),
  totalPage: Math.ceil( data.length / 10 )
});

export const searchFocus = () => ({
    type: actionTypes.SEARCH_FOCUS
});

export const searchBlur = () => ({
    type: actionTypes.SEARCH_BLUR
});

export const getList = () => {
  return (dispatch) => {
    axios.get('/api/headerList.json').then( (res) => {
      const data = res.data;
      if( data.success ) {
        dispatch( changeList( data.data ) )
      }
    }).catch( () => {
      console.log("error");
    })
  }
}

然后,我们在同目录下的reducer.js 中case 为 “CHANGE_LIST” 做如下修改。

import { SEARCH_FOCUS, SEARCH_BLUR, CHANGE_LIST } from './actionTypes';
import { fromJS } from 'immutable';

const defaultState = fromJS({
    focused: false,
    list: [],
    page: 1,
    totalPage: 1
});

export default (state = defaultState, action) => {
    switch (action.type) {
        case SEARCH_FOCUS :
            return state.set("focused", true);
        case SEARCH_BLUR:
            return state.set("focused", false);
        case CHANGE_LIST:
            return state.set("list", action.data).set("totalPage", action.totalPage);
        default:
            return state;
    }
}

接下来,我们改一下Header 组件,使他每次最多显示十项热门搜索关键字。如下。由于 this.props.list 是immutable 对象,不能通过方括号的方式取值,因此,我们先使用 toJS() 方法将它转换为js对象。

  getListArea = () => {
    const {focused, list, page} = this.props;
    const jsList = list.toJS();
    const pageList = [];

    for (let i = (page-1) * 10; i< page * 10; i++) {
      pageList.push(<SearchInfoItem key={jsList[i]}>{jsList[i]}</SearchInfoItem>)
    }
    if (focused) {
      return (
        <SearchInfo>
              <SearchInfoTitle>
                热门搜索
                <SearchInfoSwitch>换一批</SearchInfoSwitch>
              </SearchInfoTitle>
              <div>
                {pageList}
              </div>
            </SearchInfo>
      )
    } else {
      return null;
    }
  };

接着,我们需要修改一个点。热门搜索框框,并不仅在 搜索框获得焦点的时候出现。在鼠标在热门搜索框内时,也是出现的。鼠标移出这个框时会消失。

然后我们在 src/common/header/store 下的 reducer.js 中再定义一个变量 mouseIn,如下。

import { SEARCH_FOCUS, SEARCH_BLUR, CHANGE_LIST } from './actionTypes';
import { fromJS } from 'immutable';

const defaultState = fromJS({
    focused: false,
    list: [],
    mouseIn: false,
    page: 1,
    totalPage: 1
});

export default (state = defaultState, action) => {
    switch (action.type) {
        case SEARCH_FOCUS :
            return state.set("focused", true);
        case SEARCH_BLUR:
            return state.set("focused", false);
        case CHANGE_LIST:
            return state.set("list", action.data).set("totalPage", action.totalPage);
        default:
            return state;
    }
}

然后,在src/comon/header 下的 index.js 中 SearchInfo 组件添加一个 onMouseEnter 方法,如下。

  getListArea = () => {
    const {focused, list, page, handleMouseEnter} = this.props;
    const jsList = list.toJS();
    const pageList = [];

    for (let i = (page-1) * 10; i< page * 10; i++) {
      pageList.push(<SearchInfoItem key={jsList[i]}>{jsList[i]}</SearchInfoItem>)
    }
    if (focused) {
      return (
        <SearchInfo onMouseEnter={handleMouseEnter}>
          <SearchInfoTitle>
            热门搜索
            <SearchInfoSwitch>换一批</SearchInfoSwitch>
          </SearchInfoTitle>
          <div>
            {pageList}
          </div>
        </SearchInfo>
      )
    } else {
      return null;
    }
  };

再在 mapDispatchToProps 中添加上 handleMouseEnter 方法,如下。

const mapDispatchToProps = (dispatch) => {
  return {
    handleFocus () {
      dispatch(actionCreators.getList());
      dispatch(actionCreators.searchFocus());
    },
    handleBlur () {
      dispatch(actionCreators.searchBlur());
    },
    handleMouseEnter () {
      dispatch(actionCreators.mouseEnter());
    }

  }
}

再在 actionCreators.js 中创建这个action,如下。

export const mouseEnter = () => ({
  type: actionTypes.MOUSE_ENTER
});

然后再去reducer.js 中设置一下,如下。

import { SEARCH_FOCUS, SEARCH_BLUR, CHANGE_LIST, MOUSE_ENTER } from './actionTypes';
import { fromJS } from 'immutable';

const defaultState = fromJS({
    focused: false,
    list: [],
    mouseIn: false,
    page: 1,
    totalPage: 1
});

export default (state = defaultState, action) => {
    switch (action.type) {
        case SEARCH_FOCUS :
            return state.set("focused", true);
        case SEARCH_BLUR:
            return state.set("focused", false);
        case CHANGE_LIST:
            return state.set("list", action.data).set("totalPage", action.totalPage);
        case MOUSE_ENTER:
            return state.set("mouseIn", true);
        default:
            return state;
    }
}

然后,再更改一下显示热门搜索的条件,如下。

  getListArea = () => {
    const {focused, list, page, handleMouseEnter, mouseEnter} = this.props;
    const jsList = list.toJS();
    const pageList = [];

    for (let i = (page-1) * 10; i< page * 10; i++) {
      pageList.push(<SearchInfoItem key={jsList[i]}>{jsList[i]}</SearchInfoItem>)
    }
    if (focused || mouseEnter) {
      return (
        <SearchInfo onMouseEnter={handleMouseEnter}>
          <SearchInfoTitle>
            热门搜索
            <SearchInfoSwitch>换一批</SearchInfoSwitch>
          </SearchInfoTitle>
          <div>
            {pageList}
          </div>
        </SearchInfo>
      )
    } else {
      return null;
    }
  };

同理,我们再设置一个moustOut 的属性放在redux 中,然后通过它控制热门搜索消失的条件之一。

如下是 src/common/header 下 的 index.js

import React, { Component } from 'react';
import {connect} from 'react-redux';
import {
  HeaderWrapper,
  Logo,
  Nav,
  NavItem,
  NavSearch,
  Addition,
  Button,
  SearchWrapper,
  SearchInfo,
  SearchInfoTitle,
  SearchInfoSwitch,
  SearchInfoItem
} from './style';
import '../../statics/iconfont/iconfont.css';
import { CSSTransition } from 'react-transition-group';
import { actionCreators } from './store';

class Header extends Component {
  render() {
    let { focused, handleFocus, handleBlur} = this.props;
    return (
      <HeaderWrapper>
        <Logo href='/'/>
        <Nav>
          <NavItem className='left active'>首页</NavItem>
          <NavItem className='left'>下载</NavItem>
          <NavItem className='right'>登录</NavItem>
          <NavItem className='right'>
            <span className="iconfont">&#xe636;</span>
          </NavItem>
          <SearchWrapper>
            <CSSTransition
              in={focused}
              timeout={200}
              classNames="slide"
            >
              <NavSearch
                placeholder="搜索"
                className={focused ? "focused" : ""}
                onFocus={handleFocus}
                onBlur={handleBlur}
              ></NavSearch>
            </CSSTransition>
            <span
              className={focused ? "focused iconfont" : "iconfont"}
            >&#xe623;</span>
            {this.getListArea()}
          </SearchWrapper>
        </Nav>
        <Addition>
        <Button className='writting'>
          <span className="iconfont">&#xe63a;</span>
          写文章
        </Button>
        <Button className='reg'>注册</Button>
        </Addition>
      </HeaderWrapper>
    )
  }

  getListArea = () => {
    const {focused, list, page, handleMouseEnter, mouseEnter, handleMouseLeave} = this.props;
    const jsList = list.toJS();
    const pageList = [];

    for (let i = (page-1) * 10; i< page * 10; i++) {
      pageList.push(<SearchInfoItem key={jsList[i]}>{jsList[i]}</SearchInfoItem>)
    }
    if (focused || mouseEnter) {
      return (
        <SearchInfo
          onMouseEnter={handleMouseEnter}
          onMouseLeave={handleMouseLeave}
        >
          <SearchInfoTitle>
            热门搜索
            <SearchInfoSwitch>换一批</SearchInfoSwitch>
          </SearchInfoTitle>
          <div>
            {pageList}
          </div>
        </SearchInfo>
      )
    } else {
      return null;
    }
  };

}

const mapStateToProps = (state) => {
  return {
    focused: state.get("header").get("focused"),
    list: state.get("header").get("list"),
    page: state.get("header").get("page"),
    totalPage: state.get("header").get("totalPage"),
    mouseEnter: state.get("header").get("mouseIn")
  }
}

const mapDispatchToProps = (dispatch) => {
  return {
    handleFocus () {
      dispatch(actionCreators.getList());
      dispatch(actionCreators.searchFocus());
    },
    handleBlur () {
      dispatch(actionCreators.searchBlur());
    },
    handleMouseEnter () {
      dispatch(actionCreators.mouseEnter());
    },
    handleMouseLeave () {
      dispatch(actionCreators.mouseLeave());
    }

  }
}

export default connect(mapStateToProps, mapDispatchToProps)(Header);

下面是src/common/header/store 下的 actionCreators.js 

import * as actionTypes from './actionTypes';
import axios from 'axios';
import { fromJS } from 'immutable';
import '../../../mockdata.js';

const changeList = (data) => ({
  type: actionTypes.CHANGE_LIST,
  data: fromJS(data),
  totalPage: Math.ceil( data.length / 10 )
});

export const searchFocus = () => ({
    type: actionTypes.SEARCH_FOCUS
});

export const searchBlur = () => ({
    type: actionTypes.SEARCH_BLUR
});

export const getList = () => {
  return (dispatch) => {
    axios.get('/api/headerList.json').then( (res) => {
      const data = res.data;
      if( data.success ) {
        dispatch( changeList( data.data ) )
      }
    }).catch( () => {
      console.log("error");
    })
  }
}

export const mouseEnter = () => ({
  type: actionTypes.MOUSE_ENTER
});

export const mouseLeave = () => ({
  type: actionTypes.MOUSE_LEAVE
});

下面是src/common/header/store 下的reducer.js 

import { SEARCH_FOCUS, SEARCH_BLUR,
    CHANGE_LIST, MOUSE_ENTER,MOUSE_LEAVE
} from './actionTypes';
import { fromJS } from 'immutable';

const defaultState = fromJS({
    focused: false,
    list: [],
    mouseIn: false,
    page: 1,
    totalPage: 1
});

export default (state = defaultState, action) => {
    switch (action.type) {
        case SEARCH_FOCUS :
            return state.set("focused", true);
        case SEARCH_BLUR:
            return state.set("focused", false);
        case CHANGE_LIST:
            return state.set("list", action.data).set("totalPage", action.totalPage);
        case MOUSE_ENTER:
            return state.set("mouseIn", true);
        case MOUSE_LEAVE:
            return state.set("mouseIn", false);
        default:
            return state;
    }
}

然后呢,我们可以去实现一下,点击“换一批”,热门搜索关键字就换成下十个。

先更改一下 Header 组件的代码,如下

  getListArea = () => {
    const {focused, list, page, handleMouseEnter,
      mouseEnter, handleMouseLeave, handleChangeKeyWord, totalPage
    } = this.props;
    const jsList = list.toJS();
    const pageList = [];
    if (jsList.length) {
      for (let i = (page-1) * 10; i< page * 10; i++) {
        if (i >= jsList.length) {
          break;
        }
        pageList.push(<SearchInfoItem key={jsList[i]}>{jsList[i]}</SearchInfoItem>)
      }
    }
    if (focused || mouseEnter) {
      return (
        <SearchInfo
          onMouseEnter={handleMouseEnter}
          onMouseLeave={handleMouseLeave}
        >
          <SearchInfoTitle>
            热门搜索
            <SearchInfoSwitch onClick={() => handleChangeKeyWord(page, totalPage)}>
              换一批
            </SearchInfoSwitch>
          </SearchInfoTitle>
          <div>
            {pageList}
          </div>
        </SearchInfo>
      )
    } else {
      return null;
    }
  };

const mapDispatchToProps = (dispatch) => {
  return {
    handleFocus () {
      dispatch(actionCreators.getList());
      dispatch(actionCreators.searchFocus());
    },
    handleBlur () {
      dispatch(actionCreators.searchBlur());
    },
    handleMouseEnter () {
      dispatch(actionCreators.mouseEnter());
    },
    handleMouseLeave () {
      dispatch(actionCreators.mouseLeave());
    },
    handleChangeKeyWord (page, totalPage) {
      let newPage = (page) % totalPage + 1;
      dispatch(actionCreators.changekeyword(newPage));
    }

  }
}

然后改一下 actionCreators.js 

export const changekeyword = (page) => ({
  type: actionTypes.CHANGE_KEY_WORD,
  data: page
});

再改改reducer.js

import { SEARCH_FOCUS, SEARCH_BLUR,
    CHANGE_LIST, MOUSE_ENTER,
    MOUSE_LEAVE, CHANGE_KEY_WORD
} from './actionTypes';
import { fromJS } from 'immutable';

const defaultState = fromJS({
    focused: false,
    list: [],
    mouseIn: false,
    page: 1,
    totalPage: 1
});

export default (state = defaultState, action) => {
    switch (action.type) {
        case SEARCH_FOCUS :
            return state.set("focused", true);
        case SEARCH_BLUR:
            return state.set("focused", false);
        case CHANGE_LIST:
            return state.set("list", action.data).set("totalPage", action.totalPage);
        case MOUSE_ENTER:
            return state.set("mouseIn", true);
        case MOUSE_LEAVE:
            return state.set("mouseIn", false);
        case CHANGE_KEY_WORD:
            return state.set("page", action.data);
        default:
            return state;
    }
}

最后,我们把src/common/header/store 下的reducer 中 set 很多值时,用merge 方法代码,如下。

export default (state = defaultState, action) => {
    switch (action.type) {
        case SEARCH_FOCUS :
            return state.set("focused", true);
        case SEARCH_BLUR:
            return state.set("focused", false);
        case CHANGE_LIST:
            return state.merge({
                "list": action.data,
                "totalPage": action.totalPage
            });
        case MOUSE_ENTER:
            return state.set("mouseIn", true);
        case MOUSE_LEAVE:
            return state.set("mouseIn", false);
        case CHANGE_KEY_WORD:
            return state.set("page", action.data);
        default:
            return state;
    }
}

Done.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值