Skip to content

排行榜单模块开发 ​

本节目标:理解“排行榜单模块开发”的核心思路,并能把它用于实际开发或面试表达。 数据层开发axios 请求代码 ==在== api/request.js ==中,添加以下代码==

:
export const getRankListRequest = () => {  return axiosInstance.get (`/toplist/detail`);};
redux

层开发 ==排行榜单可以说是整个应用中就数据层而言最简单的一个组件。因此== redux ==的代码我们集中在一个文件中。==

//rank/store/index.jsimport { fromJS } from 'immutable';import { getRankListRequest } from '../../../api/request';
//constantsexport const CHANGE_RANK_LIST = 'home/rank/CHANGE_RANK_LIST';export const CHANGE_LOADING = 'home/rank/CHANGE_LOADING';
//actionCrreatorconst changeRankList = (data) => ({  type: CHANGE_RANK_LIST,  data: fromJS (data)})
export const getRankList = () => {  return dispatch => {    getRankListRequest ().then (data => {      let list = data && data.list;      dispatch (changeRankList (list));      dispatch (changeLoading (false));    })  }}
const changeLoading = (data) => ({  type: CHANGE_LOADING,  data})
//reducerconst defaultState = fromJS ({  rankList: [],  loading: true})
const reducer = (state = defaultState, action) => {  switch (action.type) {    case CHANGE_RANK_LIST:      return state.set ('rankList', action.data);    case CHANGE_LOADING:      return state.set ('loading', action.data);    default:      return state;  }}
export { reducer };

组件连接 redux ==先在全局== store ==注册==

:
//src/store/reducer.jsimport { combineReducers } from 'redux-immutable';import { reducer as recommendReducer } from '../application/Recommend/store/index';import { reducer as singersReducer } from '../application/Singers/store/index';import { reducer as rankReducer } from '../application/Rank/store/index';
export default combineReducers ({  //

==之后开发具体功能模块的时候添加==

 reducer  recommend: recommendReducer,  singers: singersReducer ,  rank: rankReducer});

==然后让== rank ==组件连接==

 redux,
import React, { useEffect } from 'react';import { connect } from 'react-redux';
function Rank (props) {
}
//

==映射== Redux ==全局的== state ==到组件的== props ==上==

const mapStateToProps = (state) => ({  rankList: state.getIn (['rank', 'rankList']),  loading: state.getIn (['rank', 'loading']),});//

==映射== dispatch ==到== props ==上==

const mapDispatchToProps = (dispatch) => {  return {    getRankListDataDispatch () {      dispatch (getRankList ());    }  }};
export default connect (mapStateToProps, mapDispatchToProps)(React.memo (Rank));

==已经熟悉了== redux ==开发方式的你,是不是也觉得非常简单呢?废话不多说,我们马上进入== Rank ==组件的开发。== Rank 组件开发 ==首先初始化相应的== props==。== (==这里的引入模块的代码大家自行参考== GitHub ==仓库的== chapter5 ==分支,也根据命令行报错提示依次引入==

)
const { rankList:list, loading } = props;
const { getRankListDataDispatch } = props;
let rankList = list ? list.toJS () : [];
didMount

==的时候发送== Ajax ==请求==

:
useEffect (() => {  getRankListDataDispatch ();}, []);

==排行榜单分为两个部分,一部分是官方榜,另一部分是全球榜。== ==官方榜单数据有== tracks ==数组,存放部分歌曲信息,而全球榜没有。== ==但是后端数据并没有将这两者分开,因此我们需要做一下数据的处理。==

let globalStartIndex = filterIndex (rankList);let officialList = rankList.slice (0, globalStartIndex);let globalList = rankList.slice (globalStartIndex);

==其中,==filterIndex ==从== api/utils.js ==中导出,== // ==处理数据,找出第一个没有歌名的排行榜的索引==

export const filterIndex = rankList => {  for (let i = 0; i < rankList.length - 1; i++) {    if (rankList [i].tracks.length && !rankList [i + 1].tracks.length) {      return i + 1;    }  }};
//

==记得引入这个方法==

import { filterIndex } from '../../api/utils';
//

==这是渲染榜单列表函数,传入== global ==变量来区分不同的布局方式==

const renderRankList = (list, global) => {  return (    <List globalRank={global}>      {      list.map ((item) => {        return (          <ListItem key={item.coverImgId} tracks={item.tracks} onClick={() => enterDetail (item.name)}>            <div className="img_wrapper">              <img src={item.coverImgUrl} alt=""/>              <div className="decorate"></div>              <span className="update_frequecy">{item.updateFrequency}</span>            </div>            { renderSongList (item.tracks)  }          </ListItem>        )      })    }     </List>  )}
const renderSongList = (list) => {  return list.length ? (    <SongList>      {        list.map ((item, index) => {          return <li key={index}>{index+1}. {item.first} - {item.second}</li>        })      }    </SongList>  ) : null;}
//

==榜单数据未加载出来之前都给隐藏==

let displayStyle = loading ? {"display":"none"}:  {"display": ""};
return (  <Container>    <Scroll>      <div>        <h1 className="offical" style={displayStyle}>

==官方榜==

 </h1>          { renderRankList (officialList) }        <h1 className="global" style={displayStyle}>

==全球榜==

 </h1>          { renderRankList (globalList, true) }        { loading ? <EnterLoading><Loading></Loading></EnterLoading> : null }      </div>    </Scroll>     {renderRoutes (props.route.routes)}  </Container>  );
style.js

==中==

:
import styled from'styled-components';import style from '../../assets/global-style';
// Props

==中的== globalRank ==和== tracks.length ==均代表是否为全球榜==


export const Container = styled.div`  position: fixed;  top: 90px;  bottom: 0;  width: 100%;  .offical,.global {    margin: 10px 5px;    padding-top: 15px;    font-weight: 700;    font-size: ${style ["font-size-m"]};    color: ${style ["font-color-desc"]};  }`;export const List = styled.ul`  margin-top: 10px;  padding: 0 5px;  display: ${props => props.globalRank ? "flex": "" };  flex-direction: row;  justify-content: space-between;  flex-wrap: wrap;  background: ${style ["background-color"]};  &::after {    content:"";    display:block;    width: 32vw;  }`export const ListItem = styled.li`  display: ${props => props.tracks.length ? "flex": ""};  padding: 3px 0;  border-bottom: 1px solid ${style ["border-color"]};  .img_wrapper {    width:  ${props => props.tracks.length ? "27vw": "32vw"};    height: ${props => props.tracks.length ? "27vw": "32vw"};    border-radius: 3px;    position: relative;    .decorate {      position: absolute;      bottom: 0;      width: 100%;      height: 35px;      border-radius: 3px;      background: linear-gradient (hsla (0,0%,100%,0),hsla (0,0%,43%,.4));    }    img {      width: 100%;      height: 100%;      border-radius: 3px;    }    .update_frequecy {      position: absolute;      left: 7px;      bottom: 7px;      font-size: ${style ["font-size-ss"]};      color: ${style ["font-color-light"]};    }  }`;export const SongList = styled.ul`  flex: 1;  display: flex;  flex-direction: column;  justify-content: space-around;  padding: 10px 10px;  >li {    font-size: ${style ["font-size-s"]};    color: grey;  }`;

==然后在== index.js ==中引入== CSS ==组件即可,代码就不展示了。== ==在== image_wrapper ==中,我们再次利用渐变效果实现了一层遮罩,达到衬托文字的效果。== ==其实布局都是非常常用的== flex ==布局,我就不在这上面浪费时间了。值得注意的是,当== flex ==布局一行填满三个元素,但是最后一行只有两个元素的时候,会出现一些问题,你会发现最后一个元素并不是在居中的位置,而是在最右边,中间留出了空白。我当时就遇到了这个问题,最后采用伪元素的方式才得以解决==

:
export const List = styled.ul`  margin-top: 10px;  padding: 0 5px;  display: ${props => props.globalRank ? "flex": "" };  flex-direction: row;  justify-content: space-between;  flex-wrap: wrap;  background: ${style ["background-color"]};  &::after {    content:"";    display:block;    width: 32vw;  }`

==现在的接口列表数据比之前少了一条,因此不再存在这个问题,但是希望大家能了解到这个细节。== > 来自

 <https://juejin.im/book/5da96626e51d4524ba0fd237/section/5da9773fe51d4524cb1f92bd>

本站总访问 — 次