Appearance
排行榜单模块开发
本节目标:理解“排行榜单模块开发”的核心思路,并能把它用于实际开发或面试表达。 数据层开发
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>