天天看點

基于React全家桶開發「網易雲音樂PC」項目實戰(四)

前言

前言

hello大家好我是「風不識途」,如果首次閱讀本系列請點選,正在學習React的小夥伴可以克隆該項目,參考學習,嘗試做一些小功能,下面我們開始完成本系列最重要的音樂播放器清單▶需要完成内容如下↓; 下拉檢視
基于React全家桶開發「網易雲音樂PC」項目實戰(四)

項目預覽和源碼

  • 線上預覽位址👉:點我跳轉到雲音樂
  • 項目

    Gihub

    位址👉:Musci 163 (如果覺得項目還不錯的話 👏,就給個 star ⭐ 鼓勵一下吧~)
    • 沒有翻牆的小夥伴👉:Gitee倉庫

最近更新

更新功能

  • 登入功能:
    • 暫時隻支援“163郵箱”或“手機号”登入
    • 每日推薦歌單(隻有登入成功才能檢視)
    • 個人首頁 & 個人收藏歌單 & 評論歌曲 & 點贊歌曲評論 & 建立歌單
  • 本地存儲歌曲清單:
    • 不管之後是否重新整理浏覽器,隻要在歌曲清單中就會持久化存儲
    • (重新整理浏覽器,歌曲清單依然存在)
  • 歌曲清單:
    • 對歌曲清單支援拖拽排序,并會對播放順序進行改變
  • 搜尋音樂框:
    • 優化在搜尋歌曲時,支援鍵盤"↑"+"↓"來切換搜尋歌曲内容
  • 頭部進度條:
    • 在頁面路由跳轉&網絡請求時"添加頭部進度條"顯示
  • 404頁:
    • 添加404頁,在路由沒有比對的頁面時,會顯示404頁面

修改BUG&ToDoList

點選檢視👉近期優化調整

點選檢視👉TO-DO-LIST

界面功能展示(新開發)

歌曲搜尋(↑↓選擇)

基于React全家桶開發「網易雲音樂PC」項目實戰(四)

支援對歌曲清單進行拖拽排序

基于React全家桶開發「網易雲音樂PC」項目實戰(四)

登入示範

基于React全家桶開發「網易雲音樂PC」項目實戰(四)

每日推薦

基于React全家桶開發「網易雲音樂PC」項目實戰(四)

個人首頁

基于React全家桶開發「網易雲音樂PC」項目實戰(四)

音樂清單

下面開始完成本節(稍複雜),歌曲清單播放元件,支援功能如下:
  • 支援點選某一項播放歌曲
  • 歌詞實時滾動
  • 和首頁的歌詞元件互斥效果
  • 清除全部歌曲
  • 拖拽更改順序
基于React全家桶開發「網易雲音樂PC」項目實戰(四)

1.頁面布局搭建

  1. 頁面布局搭建
    • 下拉檢視
      基于React全家桶開發「網易雲音樂PC」項目實戰(四)
  2. 點選按鈕顯示和隐藏(播放清單) 和 添加過渡效果
    • 下拉檢視
      基于React全家桶開發「網易雲音樂PC」項目實戰(四)
  3. 和歌詞展示控件互斥.(歌詞清單顯示,關閉歌詞展示)
    • 下拉檢視
      基于React全家桶開發「網易雲音樂PC」項目實戰(四)
  4. Conten内容搭建
    • 下拉檢視
      基于React全家桶開發「網易雲音樂PC」項目實戰(四)
  5. 實作點選一項,播放對應的音樂,并且背景高亮
    • 在點選目前項後,将

      id

      傳遞函數,根據

      id

      派發

      action

      ,請求播放清單詳情資訊
    • 将播放音樂函數傳遞給子元件
    • 實作當音樂播放結束或手動點選上一首或後下一首:
      • 對應

        item

        背景高亮跟着切換 (根據儲存在

        redux

        中的

        currentSongIndex

        )
    • 實作效果
      基于React全家桶開發「網易雲音樂PC」項目實戰(四)
  6. 實作點選删除按鈕,阻止事件冒泡和清除點選播放歌曲
  7. 點選清除全部按鈕,清除全部音樂,并播放下一首音樂
    • 實作效果
      基于React全家桶開發「網易雲音樂PC」項目實戰(四)

2.歌詞高亮效果

歌詞接口

  • 請求接口:
    • http://39.102.36.212:3000/lyric?id=歌曲ID
    • http://39.102.36.212:3000/lyric?id=167876
  • 對請求下來的歌詞進行解析
    • 在上一節咱們已經存放到

      redux

      當中,參考👉歌詞格式化
  • 實作目前播放的歌詞高亮顯示,擷取目前是否播放狀态滾動歌詞

3.歌詞滾動效果

  • 根據目前播放歌詞的

    index

    ,實作滾動效果
  • 擷取

    DOM

    ,計算

    scrollTop

    ,實作滾動
基于React全家桶開發「網易雲音樂PC」項目實戰(四)

音樂清單拖拽排序sortablejs

說明

  • 當需要對某些表格的行或者列進行拖拽排序時
    • 并不局限表格
    • 隻要是你想拖拽的某一行都可以

使用拖拽排序步驟

  1. 安裝
npm install sortablejs --save
yarn add sortablejs
           
  1. 導入
  1. 配置參數
import React, { useRef } from 'react';

// other hook
const 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. 完成效果
基于React全家桶開發「網易雲音樂PC」項目實戰(四)

本地存儲音樂清單

考慮

immutable

redux-persise

互相不能相容,主要原因是

immutable

的資料格式,

redux-persist

不認識,導緻我們想把

redux

中儲存的狀态不能進行本地存儲,嘗試了

redux-persist-transform-immutable

進行轉換還是不行,可能使用的姿勢不對,有使用過的大佬請指導一下,搞了兩三次,最後隻能撤銷代碼,自己還是太菜了,哭了😥

那就換一種思路,手動的隻将歌曲清單進行本地存儲(隻存儲歌曲id),将歌曲歌曲清單中所有歌曲

id

儲存到

local Storage

預設歌曲清單

在我們每次請求歌曲的時候,其實隻需要知道歌曲

id

就可以了,這樣我們隻需要将在第一次初始化的的時候将

歌曲id

進行存儲在本地就可以了,不過需要對本地存儲的

歌曲id

進行去重就可以了(重複的

歌曲id

不進行本地存儲)

基于React全家桶開發「網易雲音樂PC」項目實戰(四)

實作效果

基于React全家桶開發「網易雲音樂PC」項目實戰(四)

歌曲順序(異步問題)

一個小問題:在我們周遊歌曲清單數組

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

    數組順序進行請求了
基于React全家桶開發「網易雲音樂PC」項目實戰(四)

以優化

  • 支援記憶歌曲清單
    • 重新整理頁面後,音樂播放清單可以記憶上次播放順序
  • 記憶在關閉頁面前播放的音樂
    • 重新整理頁面後,關閉頁面前記憶目前播放的歌曲,再次打開時預設歌曲是關閉前播放的歌曲
到現在我們已經完成「網易雲音樂PC」基本功能,相信你對

React

全家桶已經是比較熟練了,接下來想往哪方面擴充可以自行補充完善功能;

如果文章中有哪部分不明白的或寫的不好或是有什麼建議歡迎大家提出🤗,希望和大家共同進步;

感謝

  • 非常感謝王紅元老師的React核心技術實戰讓我學習到很多 react 的知識。
  • 非常感謝背景提供者Binaryify,接口很穩定,文檔很完善