接着前面的继续写了,这篇博客就写这两个页面,下一篇就主要讲歌曲播放功能,进度条拉伸以及歌曲时间的变化了


先完成新碟上架Demo

一.第一步不用说肯定是先获取我们这个数据对吧

去到我们services文件夹里面的recommend.js

export function getNewAlbums(limit) {return request({url: "/top/album",params: {limit,}})
}

二.就要把这个数据存储到我们的redux中了


到这个store,我们是每个部分里面都有一个子redux,然后再通过合并到我们的主redux里面

首先肯定是定义常量了

constants.js

export const CHANGE_NEW_ALBUM = "recommend/CHANGE_NEW_ALBUM";

然后去actionCreators.js写方法

import * as actionTypes from './constants';import { getNewAlbums
} from '@/services/recommend';const changeNewAlbumAction = (res) => ({type: actionTypes.CHANGE_NEW_ALBUM,newAlbums: res.albums
})export const getNewAlbumAction = (limit) => {return dispatch => {getNewAlbums(limit).then(res => {dispatch(changeNewAlbumAction(res));})}
}

然后去reducer.js中

import { Map } from 'immutable';
//导入所有常量
import * as actionTypes from './constants';const defaultState = Map({newAlbums: [],
});function reducer(state = defaultState, action) {switch (action.type) {case actionTypes.CHANGE_NEW_ALBUM:return state.set("newAlbums", action.newAlbums);default:return state;}
}export default reducer;

三.这个时候就得去我们的组件中通过redux-hooks发送网络请求了

在recommend中的c-cpns里面创建一个new-album文件夹,里面在创建一个index.js,一个style.js

index.js

还是分三步来写,第一步写我们导入的配置

import React, { memo,useEffect,useRef } from 'react';import {useDispatch, useSelector, shallowEqual} from 'react-redux'import { getNewAlbumAction } from '../../store/actionCreators';import { Carousel } from 'antd';
import HYAlbumCover from '@/components/album-cover';
import HYThemeHeaderRCM from '@/components/theme-header-rcm';
import { AlbumWrapper } from './style';

HYAlbumCover,HYThemeHeaderRCM这两个组件是我在components中定义的复用型组件

下面来写一下这个组件,HYAlbumCover

在components中创建一个album-cover文件夹,里面在创建一个index.js,一个style.js

index.js

import React, { memo } from 'react';import { getSizeImage } from '@/utils/format-utils';import { AlbumWrapper } from './style';export default memo(function HYAlbumCover(props) {// state and propsconst { info, size = 130, width = 153, bgp = "-845px" } = props;return (<AlbumWrapper size={size} width={width} bgp={bgp}><div className="album-image"><img src={getSizeImage(info.picUrl, size)} alt="" /><a href="/todo" className="cover image_cover">{info.name}</a></div><div className="album-info"><div className="name text-nowrap">{info.name}</div><div className="artist text-nowrap">{info.artist.name}</div></div></AlbumWrapper>)
})

getSizeImage是什么,之前的文章提到过,网易云音乐为了加快图片的加载速度,在图片后面可以拼接一个param参数,然后传入宽高,这样就可以让我们的图片变为我们传入的宽高,这样加载的时候就很快

style.js

import styled from 'styled-components';export const AlbumWrapper = styled.div`width: ${props => props.width + "px"};.album-image {position: relative;width: ${props => props.width + "px"};height: ${props => props.size + "px"};overflow: hidden;margin-top: 15px;img {width: ${props => props.size + "px"};height: ${props => props.size + "px"};}.cover {position: absolute;left: 0;right: 0;top: 0;bottom: 0;background-position: 0 ${props => props.bgp};text-indent: -9999px;}}.album-info {font-size: 12px;width: ${props => props.size};.name {color: #000;white-space: nowrap;text-overflow: ellipsis;overflow: hidden;}.artist {color: #666;}}
`

HYThemeHeaderRCM这个组件,我就不写了,之前的文章写过

然后看第二步,逻辑代码,我把上面的也复制过来吧

import React, { memo,useEffect,useRef } from 'react';
import {useDispatch, useSelector, shallowEqual} from 'react-redux'
import { getNewAlbumAction } from '../../store/actionCreators';
import { Carousel } from 'antd';
import HYAlbumCover from '@/components/album-cover';
import HYThemeHeaderRCM from '@/components/theme-header-rcm';
import { AlbumWrapper } from './style';export default memo(function HYNewAlbum() {const {newAlbums} = useSelector(state =>({newAlbums:state.getIn(['recommend','newAlbums'])}),shallowEqual)const dispath = useDispatch()// other hooksconst pageRef = useRef();useEffect(()=>{dispath(getNewAlbumAction(10))},[dispath])
})

useSelector就是获取我们redux中定义的state,shallowEqual是为了浅层比较,性能优化,然后就在useEffect中请求我们储存在redux中的数据

第三步

return (<AlbumWrapper><HYThemeHeaderRCM title="新碟上架"/><div className="content"><button className="arrow arrow-left sprite_02" onClick={e => pageRef.current.prev()}></button><div className="album"><Carousel dots={false} ref={pageRef}>{[0, 1].map(item => {return (<div key={item} className="page">{newAlbums.slice(item * 5, (item + 1) * 5).map(iten => {return <HYAlbumCover key={iten.id} info={iten} size={100} width={118} bgp="-570px"/>})}</div>)})}</Carousel></div><button className="arrow arrow-right sprite_02"onClick={e => pageRef.current.next()}></button></div></AlbumWrapper>)

这个地方的数据我用slice处理了一下,因为它一次就展示5条,当点击next时候就展示另外5条,prev也是

然后就是我们的style.js

import styled from "styled-components";export const AlbumWrapper = styled.div`margin-top: 50px;.content {height: 186px;background-color: #f5f5f5;border: 1px solid #d3d3d3;margin: 20px 0 37px;display: flex;align-items: center;.arrow {width: 25px;height: 25px;cursor: pointer;}.arrow-left {background-position: -260px -75px;}.arrow-right {background-position: -300px -75px;}.album {width: 640px;height: 150px;.ant-carousel .slick-slide {height: 150px;overflow: hidden;}.page {display: flex !important;justify-content: space-between;align-items: center;}}}
`

ok,这个页面完成了,下面就开始写这个页面了


第一步,首先定义网络请求数据

去到我们services文件夹里面的recommend.js

export function getTopList(idx) {return request({url: "/top/list",params: {idx}})
}

第二步,就得把数据存储到我们的redux里面了

还是先定义常量

constants.js

export const CHANGE_UP_RANKING = "recommend/CHANGE_UP_RANKING";
export const CHANGE_NEW_RANKING = "recommend/CHANGE_New_RANKING";
export const CHANGE_ORIGIN_RANKING = "recommend/CHANGE_ORIGIN_RANKING";

actionCreators.js

import * as actionTypes from './constants';import { getTopList
} from '@/services/recommend';
const changeUpRankingAction = (res) => ({type: actionTypes.CHANGE_UP_RANKING,upRanking: res.playlist
})const changeNewRankingAction = (res) => ({type: actionTypes.CHANGE_NEW_RANKING,newRanking: res.playlist
})const changeOriginRankingAction = (res) => ({type: actionTypes.CHANGE_ORIGIN_RANKING,originRanking: res.playlist
})
export const getTopListAction = (idx) => {return dispatch => {getTopList(idx).then(res => {switch (idx) {case 0:dispatch(changeUpRankingAction(res));break;case 2:dispatch(changeNewRankingAction(res));break;case 3:dispatch(changeOriginRankingAction(res));break;default:}});}
}

再去我们的reducer.js中

import { Map } from 'immutable';//导入所有常量
import * as actionTypes from './constants';const defaultState = Map({upRanking: {},newRanking: {},originRanking: {},
});function reducer(state = defaultState, action) {switch (action.type) {case actionTypes.CHANGE_UP_RANKING:return state.set("upRanking", action.upRanking);case actionTypes.CHANGE_NEW_RANKING:return state.set("newRanking", action.newRanking);case actionTypes.CHANGE_ORIGIN_RANKING:return state.set("originRanking", action.originRanking);default:return state;}
}export default reducer;

第三步,就可以去组件里面写内容了

在recommend中的c-cpns里面创建一个recommend-ranking文件夹,里面在创建一个index.js,一个style.js

index.js

还是分三步,第一步导入配置

import React, { memo, useEffect } from 'react';
import { useDispatch, useSelector, shallowEqual } from 'react-redux';import HYThemeHeaderRCM from '@/components/theme-header-rcm';
import HYTopRanking from '@/components/top-ranking';
import { RankingWrapper } from './style';
import { getTopListAction } from '../../store/actionCreators';

HYThemeHeaderRCM这个组件之前的博客封装过就不写了,接下来要写的那个列表,三块很明显是一模一样的,所以封装一个组件HYTopRanking

在components文件夹中创建一个top-ranking文件夹,里面创建一个index.js,一个style.js

index.js

import React, { memo } from 'react';import { getSizeImage } from '@/utils/format-utils';import { TopRankingWrapper } from './style';export default memo(function HYTopRanking(props) {const { info } = props;const { tracks = [] } = info;return (<TopRankingWrapper><div className="header"><div className="image"><img src={getSizeImage(info.coverImgUrl)} alt="" /><a href="/todo" className="image_cover">ranking</a></div><div className="info"><a href="/todo">{info.name}</a><div><button className="btn play sprite_02"></button><button className="btn favor sprite_02"></button></div></div></div><div className="list">{tracks.slice(0, 10).map((item, index) => {return (<div key={item.id} className="list-item"><div className="rank">{index + 1}</div><div className="info"><span className="name text-nowrap">{item.name}</span><div className="operate"><button className="btn sprite_02 play"></button><button className="btn sprite_icon2 addto"></button><button className="btn sprite_02 favor"></button></div></div></div>)})}</div><div className="footer"><a href="/todo">查看全部 &gt;</a></div></TopRankingWrapper>)
})

style.js

import styled from 'styled-components';export const TopRankingWrapper = styled.div`flex: 1;.header {height: 100px;display: flex;margin: 20px 0 0 20px;.image {width: 80px;height: 80px;position: relative;img {width: 80px;height: 80px;}}.info {margin: 5px 0 0 10px;a {font-size: 14px;color: #333;font-weight: 700;}.btn {display: inline-block;text-indent: -9999px;width: 22px;height: 22px;margin: 8px 10px 0 0;cursor: pointer;}.play {background-position: -267px -205px;}.favor {background-position: -300px -205px;}}}.list {.list-item {position: relative;display: flex;align-items: center;height: 32px;:nth-child(-n+3) .rank {color: #c10d0c;}.rank {width: 35px;text-align: center;margin-left: 10px;font-size: 16px;}.info {color: #000;width: 170px;height: 17px;line-height: 17px;display: flex;justify-content: space-between;.name {flex: 1;}.operate {display: flex;align-items: center;display: none;width: 82px;.btn {width: 17px;height: 17px;margin-left: 8px;cursor: pointer;}.play {background-position: -267px -268px;}.addto {position: relative;top: 2px;background-position: 0 -700px;}.favor {background-position: -297px -268px;}}}&:hover {.operate {display: block;}}}}.footer {height: 32px;display: flex;align-items: center;margin-right: 32px;justify-content: flex-end;a {color: #000;}}
`

好了,接下来开始第二步,逻辑代码

export default memo(function HYRecomendRanking() {// redux hooksconst { upRanking, newRanking, originRanking } = useSelector(state => ({upRanking: state.getIn(["recommend", "upRanking"]),newRanking: state.getIn(["recommend", "newRanking"]),originRanking: state.getIn(["recommend", "originRanking"]),}), shallowEqual);const dispatch = useDispatch();// other hooksuseEffect(() => {dispatch(getTopListAction(0));dispatch(getTopListAction(2));dispatch(getTopListAction(3));}, [dispatch]);
})

这块就没啥好说的了

第三步

 return (<RankingWrapper><HYThemeHeaderRCM title="榜单" /><div className="tops"><HYTopRanking info={upRanking}/><HYTopRanking info={newRanking}/><HYTopRanking info={originRanking}/></div></RankingWrapper>)

style.js

import styled from "styled-components";export const RankingWrapper = styled.div`.tops {margin: 30px 0;display: flex;background-image: url(${require("@/assets/img/recommend-top-bg.png")});height: 472px;}
`

好了,这个页面也完成了

下一篇就主要讲歌曲播放功能,进度条拉伸以及歌曲时间的变化了

github项目地址:https://github.com/lsh555/WYY-Music

React实现(Web端)网易云音乐项目(三),错过了真的可惜呀相关推荐

  1. React实现(Web端)网易云音乐项目(一),错过了真的可惜呀

    首先肯定是搭建项目的结构了,通过脚手架安装这部分我就不说了 首先看项目的目录结构 assets:放我们的静态资源,图片,字体和公共初始样式等 common:放我们公共的JS文件 components: ...

  2. React实现(Web端)网易云音乐项目(四),错过了真的可惜呀

    今天就写一下歌曲播放这个功能,进度条拉伸以及歌曲时间的变化,当我们改变一个状态的时候,其他几个都相应改变,这个功能还是有一点复杂的- 就是这个,当我们可以播放,暂停,当我们播放的时候,进度条改变以及歌 ...

  3. React实现(Web端)网易云音乐项目(六),错过了真的可惜呀

    今天实现歌曲播放时,歌词随着滚动的效果 网易云原本的歌词是这样的 [00:00.000] 作曲 : 许嵩 [00:01.000] 作词 : 许嵩 [00:22.240]天空好想下雨 [00:24.38 ...

  4. React实现(Web端)网易云音乐项目(二),错过了真的可惜呀

    接着上一篇来继续写了,这篇博客主要完成下面这部分 一.首先先完成这个轮播图了,那肯定需要请求数据了,所以我们先把网络请求部分先写好 在React里面我们也是通过axios来发送网络请求的,先安装 ya ...

  5. React实现(Web端)网易云音乐项目(五),错过了真的可惜呀

    今天我们做歌曲的单曲循环,按序播放,随机播放以及通过手动点击上一首,下一首这些功能哈,下一篇博客就写我们歌词滚动功能 由于我每篇都和前面是联系在一起的,如果想获取整个项目,可以去我的github下载源 ...

  6. PC端网易云音乐播放云盘音乐时显示加载失败,自动调转下一首的解决方法

    PC端网易云音乐播放云盘音乐时显示加载失败,自动调转下一首解决方法 注意: 一定要看看是不是和你的情况一样,不一样不要用这种方法!!! 具体情况: 我们经常会下载歌曲存到电脑文件夹里,然后通过网易云音 ...

  7. angular8 | 网易云音乐项目实战(一)

    angular8 网易云音乐项目实战(一) 视频教程原地址:https://www.bilibili.com/video/av70355308 本文为学习笔记 从github上clone相关源码 cs ...

  8. 微信小程序之网易云音乐(三)- 主页面底部导航、轮播图、歌单及歌曲模块开发

    微信小程序之网易云音乐(三)- 主页面底部导航.轮播图.歌单及歌曲模块开发 前言 一. 主页面底部导航 二. 轮播图区域 三. 歌单区域 四. 歌曲区域 微信小程序之网易云音乐导航 前言 创建一个新模 ...

  9. Vue2 - 网易云音乐项目笔记(基于Vant UI组件库)

    目录 一.项目技术 二.准备工作 1.初始化Vue项目 2.配置Vant UI组件库 3.下载并使用vue-router库 4.接口API 5.postcss插件 三.分析页面实现功能 1.路由页面准 ...

最新文章

  1. AI实验室•西安站 教你用人脸识别打造爆款应用
  2. 一条数据的漫游奇遇记
  3. hdu 2196(经典树形dp)
  4. HBase shell执行批量脚本
  5. 【WiFi密码破解详细图文教程】ZOL仅此一份 详细介绍从CDlinux U盘启动到设置扫描破解-破解软件论坛-ZOL中关村在线...
  6. SM3算法对大文件做摘要
  7. python pandas数据分析基础入门2——(数据格式转换、排序、统计、数据透视表)...
  8. iOS13beta2版描述文件,修复了,修复了,修复了,可以用描述文件更新了
  9. html表单中文字前黑点怎么弄,如何将word文档中标题前的黑点去掉
  10. DNS解析异常问题排查
  11. 数字IC后端工程师应该如何快速入门提高工作技能?
  12. 卓训教育:孩子不爱学习怎么办,如何让孩子将动力内化
  13. CSS 列表样式 (ul)
  14. 功能安全b等级_安全B端会议吸引了越来越多的信息安全人群
  15. windows日志查看与清理
  16. 使用python来保存win10的聚焦图片
  17. C#,.net将DataTable转为对应的Model实体类
  18. T字形路口小车如何要c语言编程,科二皮卡怎么找30公分线
  19. 【ARC 自动引用计数 Objective-C语言】
  20. 影牛社区短视频APP源码/最火短视频类APP源码下载

热门文章

  1. (百万字废话乱写+1小时2000字码字速度养成计划)网络支付与结算读书笔记1(20120720)...
  2. c语言:求正方体的表面积和体积
  3. 中国信通院的星火链主链支持与以太链(测试网)交互
  4. Android Accessibility(辅助功能) 学习
  5. python填充图像为方形
  6. 简洁版Featured Category/Shop by Category模块
  7. 【沃顿商学院学习笔记】商业分析——Customer Analytics:05 营销中的新兴数据集:营销科学的未来 EMERGING DATA SETS IN MARKETING
  8. vb6.0连接postgresql 13
  9. 找不到电脑C盘下的AppData文件夹怎么办?
  10. 【二】gym初次入门一学就会---代码详细解析简明教程----平衡杆案例