前言

前言

hello大家好我是「风不识途」,如果首次浏览本系列请点击,正在学习React的小伙伴能够克隆该我的项目,参考学习,尝试做一些小性能,上面咱们开始实现本系列最重要的音乐播放器列表▶须要实现内容如下↓;

我的项目预览和源码

  • 在线预览地址:点我跳转到云音乐
  • 我的项目Gihub地址:Musci 163 (如果感觉我的项目还不错的话 ,就给个 star ⭐ 激励一下吧~)

    • 没有翻墙的小伙伴:Gitee仓库

最近更新

更新性能

  • 登录性能:

    • 临时只反对“163邮箱”或“手机号”登录
    • 每日举荐歌单(只有登录胜利能力查看)
    • 个人主页 & 集体珍藏歌单 & 评论歌曲 & 点赞歌曲评论 & 创立歌单
  • 本地存储歌曲列表:

    • 不论之后是否刷新浏览器,只有在歌曲列表中就会长久化存储
    • (刷新浏览器,歌曲列表仍然存在)
  • 歌曲列表:

    • 对歌曲列表反对拖拽排序,并会对播放程序进行扭转
  • 搜寻音乐框:

    • 优化在搜寻歌曲时,反对键盘"↑"+"↓"来切换搜寻歌曲内容
  • 头部进度条:

    • 在页面路由跳转&网络申请时"增加头部进度条"显示
  • 404页:

    • 增加404页,在路由没有匹配的页面时,会显示404页面

批改BUG&ToDoList

点击查看近期优化调整

点击查看TO-DO-LIST

界面性能展现(新开发)

歌曲搜寻(↑↓抉择)

反对对歌曲列表进行拖拽排序

登录演示

每日举荐

个人主页

音乐列表

上面开始实现本节(稍简单),歌曲列表播放组件,反对性能如下:

  • 反对点击某一项播放歌曲
  • 歌词实时滚动
  • 和首页的歌词组件互斥成果
  • 革除全部歌曲
  • 拖拽更改程序

1.页面布局搭建

  1. 页面布局搭建

  1. 点击按钮显示和暗藏(播放列表) 和 增加过渡成果

  1. 和歌词展现控件互斥.(歌词列表显示,敞开歌词展现)

  1. Conten内容搭建

  1. 实现点击一项,播放对应的音乐,并且背景高亮

    • 在点击以后项后,将id传递函数,依据id派发action,申请播放列表详情信息
    • 将播放音乐函数传递给子组件
    • 实现当音乐播放完结或手动点击上一首或后下一首:

      • 对应item背景高亮跟着切换 (依据保留在redux中的currentSongIndex)

  1. 实现点击删除按钮,阻止事件冒泡和革除点击播放歌曲
  2. 点击革除全副按钮,革除全副音乐,并播放下一首音乐

2.歌词高亮成果

歌词接口

  • 申请接口:

    • http://39.102.36.212:3000/lyr...
    • http://39.102.36.212:3000/lyr...
  • 对申请下来的歌词进行解析

    • 在上一节咱们曾经寄存到redux当中,参考歌词格式化
  • 实现以后播放的歌词高亮显示,获取以后是否播放状态滚动歌词

3.歌词滚动成果

  • 依据以后播放歌词的 index,实现滚动成果
  • 获取DOM,计算scrollTop,实现滚动

音乐列表拖拽排序sortablejs

阐明

  • <font color='red'>当须要对某些表格的行或者列进行拖拽排序时</font>

    • 并不局限表格
    • 只有是你想拖拽的某一行都能够

应用拖拽排序步骤

  1. 装置
npm install sortablejs --saveyarn add sortablejs
  1. 导入
import Sortable from 'sortablejs';
  1. 配置参数
import React, { useRef } from 'react';// other hookconst playlistRef = useRef();// 用于获取DOM元素useEffect(() => {  // 获取列表项父元素  const el = playlistRef.current.querySelector('.main-playlist');  new Sortable(el, {    sort: true,    animation: 200,    onEnd: function (evt) {  // 拖拽完结产生该事件      let tempPlayList = playList      tempPlayList.splice(evt.newIndex, 0, playList.splice(evt.oldIndex, 1)[0]);      // 更改播放列表程序      dispatch(changePlayListAction(tempPlayList))    },  });}, [playList, dispatch]);
  1. 实现成果

本地存储音乐列表

思考immutableredux-persise互相不能兼容,次要起因是immutable的数据格式,redux-persist不意识,导致咱们想把redux中保留的状态不能进行本地存储,尝试了redux-persist-transform-immutable进行转换还是不行,可能应用的姿态不对,有应用过的大佬请领导一下,搞了两三次,最初只能撤销代码,本人还是太菜了,哭了

那就换一种思路,手动的只将歌曲列表进行本地存储(只存储歌曲id),将歌曲歌曲列表中所有歌曲id保留到local Storage

默认歌曲列表

在咱们每次申请歌曲的时候,其实只须要晓得歌曲id就能够了,这样咱们只须要将在第一次初始化的的时候将歌曲id进行存储在本地就能够了,不过须要对本地存储的歌曲id进行去重就能够了(反复的歌曲id不进行本地存储)

实现成果

歌曲程序(异步问题)

一个小问题:在咱们遍历歌曲列表数组id发送网络申请时,因为发送网络申请是异步的,导致咱们的音乐列表的歌曲程序并不是依照发送数组设定好的程序,有没有一种方法能够只有上一次网络申请胜利之后再进行发送这次网络申请呢?

答案是必定的,首先想到promise的小伙伴加鸡腿,当然也能够应用async await

思路

(1)解决方案:promise + setinterval(定时器)(2)可能有同学会问,为什么应用定时器呢?(不肯定应用要应用定时器+promise这种计划)(3)这是因为在咱们发送ajax时,不能很好的进行管制,应用一个标识变量来进行管制ajax是否发送(默认为true)(4)在每次开始定时器时,首先判断标识变量是否为true如果为true就发送ajax,  在本次申请ajax时设置标识变量为false(即在定时器中不会再发送网络申请),在本次ajax实现时(即异步操作胜利时),扭转标识变量为true  这样就能进行很好的管制,简略的总结一下:就是必须管制本次ajax发送申请胜利时,能力进行下一次ajax  (外围在于应用标识变量,来管制ajax申请,且只有上次ajax申请胜利,能力进行下一次ajax)

代码

export const getSongDetailArrayAction = (listId) => {  return (dispatch, getState) => {    // 1.获取歌曲列表    const playList = getState().getIn(['player', 'playList'])    let i = 0    let timer = null    let excuteRun = true // 管制ajax    timer = setInterval(() => {      let idx = listId[i]      new Promise((resolve, reject) => {        excuteRun &&          getSongDetail(idx).then((res) => {            excuteRun = false            // console.log(res.songs[0])            // (0)歌曲ID增加到本地存储            addPlaylistId(idx)            const song = res.songs && res.songs[0]            // console.log(song)            if (!song) return            // (1)增加到播放列表中            playList.push(song)            dispatch(changePlayListAction(playList))            // (2)更改以后播放的索引            const songIndex = playList.length - 1            dispatch(changeSongIndexAction(songIndex))            // (3)更改以后播放歌曲            dispatch(changeCurrentSongAction(song))            // (4)申请歌曲的歌词            dispatch(getLyricAction(idx))            // (5)更新歌曲数量            dispatch(changePlayListCount(playList.length))            resolve(i)          })      }).then((value) => {        excuteRun = true      })      i++      if (i >= listId.length) {        clearInterval(timer)      }    })  }}

成果

  • 这下不论刷新多少次,都会依照咱们的本地存储中歌曲列表id数组程序进行申请了

以优化

  • 反对记忆歌曲列表

    • 刷新页面后,音乐播放列表能够记忆上次播放程序
  • 记忆在敞开页背后播放的音乐

    • 刷新页面后,敞开页背后记忆以后播放的歌曲,再次关上时默认歌曲是敞开前播放的歌曲

到当初咱们曾经实现「网易云音乐PC」基本功能,置信你对React全家桶曾经是比拟纯熟了,接下来想往哪方面扩大能够自行补充欠缺性能;

如果文章中有哪局部不明确的或写的不好或是有什么倡议欢送大家提出,心愿和大家共同进步;

感激

  • 非常感谢王红元老师的React核心技术实战让我学习到很多 react 的常识。
  • 非常感谢后盾提供者Binaryify,接口很稳固,文档很欠缺