React实现(Web端)网易云音乐项目(三),错过了真的可惜呀
接着前面的继续写了,这篇博客就写这两个页面,下一篇就主要讲歌曲播放功能,进度条拉伸以及歌曲时间的变化了
先完成新碟上架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">查看全部 ></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端)网易云音乐项目(三),错过了真的可惜呀相关推荐
- React实现(Web端)网易云音乐项目(一),错过了真的可惜呀
首先肯定是搭建项目的结构了,通过脚手架安装这部分我就不说了 首先看项目的目录结构 assets:放我们的静态资源,图片,字体和公共初始样式等 common:放我们公共的JS文件 components: ...
- React实现(Web端)网易云音乐项目(四),错过了真的可惜呀
今天就写一下歌曲播放这个功能,进度条拉伸以及歌曲时间的变化,当我们改变一个状态的时候,其他几个都相应改变,这个功能还是有一点复杂的- 就是这个,当我们可以播放,暂停,当我们播放的时候,进度条改变以及歌 ...
- React实现(Web端)网易云音乐项目(六),错过了真的可惜呀
今天实现歌曲播放时,歌词随着滚动的效果 网易云原本的歌词是这样的 [00:00.000] 作曲 : 许嵩 [00:01.000] 作词 : 许嵩 [00:22.240]天空好想下雨 [00:24.38 ...
- React实现(Web端)网易云音乐项目(二),错过了真的可惜呀
接着上一篇来继续写了,这篇博客主要完成下面这部分 一.首先先完成这个轮播图了,那肯定需要请求数据了,所以我们先把网络请求部分先写好 在React里面我们也是通过axios来发送网络请求的,先安装 ya ...
- React实现(Web端)网易云音乐项目(五),错过了真的可惜呀
今天我们做歌曲的单曲循环,按序播放,随机播放以及通过手动点击上一首,下一首这些功能哈,下一篇博客就写我们歌词滚动功能 由于我每篇都和前面是联系在一起的,如果想获取整个项目,可以去我的github下载源 ...
- PC端网易云音乐播放云盘音乐时显示加载失败,自动调转下一首的解决方法
PC端网易云音乐播放云盘音乐时显示加载失败,自动调转下一首解决方法 注意: 一定要看看是不是和你的情况一样,不一样不要用这种方法!!! 具体情况: 我们经常会下载歌曲存到电脑文件夹里,然后通过网易云音 ...
- angular8 | 网易云音乐项目实战(一)
angular8 网易云音乐项目实战(一) 视频教程原地址:https://www.bilibili.com/video/av70355308 本文为学习笔记 从github上clone相关源码 cs ...
- 微信小程序之网易云音乐(三)- 主页面底部导航、轮播图、歌单及歌曲模块开发
微信小程序之网易云音乐(三)- 主页面底部导航.轮播图.歌单及歌曲模块开发 前言 一. 主页面底部导航 二. 轮播图区域 三. 歌单区域 四. 歌曲区域 微信小程序之网易云音乐导航 前言 创建一个新模 ...
- Vue2 - 网易云音乐项目笔记(基于Vant UI组件库)
目录 一.项目技术 二.准备工作 1.初始化Vue项目 2.配置Vant UI组件库 3.下载并使用vue-router库 4.接口API 5.postcss插件 三.分析页面实现功能 1.路由页面准 ...
最新文章
- AI实验室•西安站 教你用人脸识别打造爆款应用
- 一条数据的漫游奇遇记
- hdu 2196(经典树形dp)
- HBase shell执行批量脚本
- 【WiFi密码破解详细图文教程】ZOL仅此一份 详细介绍从CDlinux U盘启动到设置扫描破解-破解软件论坛-ZOL中关村在线...
- SM3算法对大文件做摘要
- python pandas数据分析基础入门2——(数据格式转换、排序、统计、数据透视表)...
- iOS13beta2版描述文件,修复了,修复了,修复了,可以用描述文件更新了
- html表单中文字前黑点怎么弄,如何将word文档中标题前的黑点去掉
- DNS解析异常问题排查
- 数字IC后端工程师应该如何快速入门提高工作技能?
- 卓训教育:孩子不爱学习怎么办,如何让孩子将动力内化
- CSS 列表样式 (ul)
- 功能安全b等级_安全B端会议吸引了越来越多的信息安全人群
- windows日志查看与清理
- 使用python来保存win10的聚焦图片
- C#,.net将DataTable转为对应的Model实体类
- T字形路口小车如何要c语言编程,科二皮卡怎么找30公分线
- 【ARC 自动引用计数 Objective-C语言】
- 影牛社区短视频APP源码/最火短视频类APP源码下载
热门文章
- (百万字废话乱写+1小时2000字码字速度养成计划)网络支付与结算读书笔记1(20120720)...
- c语言:求正方体的表面积和体积
- 中国信通院的星火链主链支持与以太链(测试网)交互
- Android Accessibility(辅助功能) 学习
- python填充图像为方形
- 简洁版Featured Category/Shop by Category模块
- 【沃顿商学院学习笔记】商业分析——Customer Analytics:05 营销中的新兴数据集:营销科学的未来 EMERGING DATA SETS IN MARKETING
- vb6.0连接postgresql 13
- 找不到电脑C盘下的AppData文件夹怎么办?
- 【二】gym初次入门一学就会---代码详细解析简明教程----平衡杆案例