preface

preface

Here’s how to create the most important music player in this series:

The drop-down to view


Project preview and source code

  • Online preview address 👉 : Click me to jump to cloud music
  • projectGihubAddress 👉 :Musci 163(If you think the project is good 👏, give a star ⭐ to encourage you ~)
    • Friends who don’t climb the wall 👉 : Gitee Warehouse

Recent updates

Update function

  • Login function:
    • Only 163 email or mobile phone number is supported for login
    • Recommended daily playlist (only available after login)
    • Personal Home Page & Personal Collection playlist & Comment songs & Like songs comment & Create playlist
  • Local store song list:
    • Regardless of whether or not the browser is refreshed later, it is persisted as long as it is in the song list
    • (Refresh the browser, the song list still exists)
  • Song List:
    • Supports drag and drop sorting for song lists, and changes the playback order
  • Search music box:
    • Optimized The keyboard ↑ + ↓ can be used to switch between songs when searching for songs
  • Header progress bar:
    • “Add header progress bar” display on page route jump & network request
  • Page 404:
    • Add 404 pages. If there is no matching page in the route, the 404 page will be displayed

Modify BUG&ToDoList

Click on 👉 for recent optimizations

Check out 👉 do-list

Interface Function Display (new development)

Song Search (↑↓ select)

Support for drag and drop sorting of song lists

Login demo

Recommended daily

Personal home page

Music list

Now start to complete this section (slightly complicated), song list player component, supporting functions are as follows:

  • You can click a certain item to play the song
  • Lyrics scrolling in real time
  • And the first page of the lyrics component mutually exclusive effect
  • Clear all songs
  • Drag to change the order

1. Set up page layout

  1. Page layout setup

    • The drop-down to view


  2. Click the button to show and hide (playlist) and add transition effects

    • The drop-down to view


  3. And lyrics display control mutually exclusive (lyrics list display, turn off lyrics display)

    • The drop-down to view


  4. Conten Content construction

    • The drop-down to view


  5. Click on an item, play the corresponding music, and highlight the background

    • After the current item is clicked, the id is passed to the function and an action is issued based on the ID, requesting playlist details

    • Pass the play music function to the child component

    • Implement when the music ends or manually click on the previous or next song:

      • The correspondingitemBackground highlighting toggles along (according to saved inreduxIn thecurrentSongIndex)
    • Implementation effect


  6. Implement click delete button to prevent events from bubbling and clear click to play songs

  7. Click the Clear All button to clear all music and play the next music

    • Implementation effect


2. Lyrics highlighting

The lyrics interface

  • Request interface:

    • Song ID http://39.102.36.212:3000/lyric?id=
    • http://39.102.36.212:3000/lyric?id=167876
  • Parse the requested lyrics

    • In the last video we stored itreduxFor details, see 👉Lyrics formatting
  • Achieve the current play of the lyrics highlighted, get the current play status of the scroll lyrics

3. Rolling effect of lyrics

  • Based on the current playing lyricsindexTo achieve the scrolling effect
  • To obtainDOMTo calculate thescrollTop, realize scrolling

Music list drag-and-drop sort sorTableJS

instructions

  • When a row or column of some table needs to be dragged and sorted
    • Not limited to tables
    • You can drag any row you want

Use the drag and drop sort step

  1. The installation
npm install sortablejs --save
yarn add sortablejs
Copy the code
  1. The import
import Sortable from 'sortablejs';
Copy the code
  1. Configuration parameters
import React, { useRef } from 'react';

// other hook
const playlistRef = useRef();// Get the DOM element

useEffect(() = > {
  // Get the list item parent element
  const el = playlistRef.current.querySelector('.main-playlist');
  new Sortable(el, {
    sort: true.animation: 200.onEnd: function (evt) {  // The event occurs when the drag ends
      let tempPlayList = playList
      tempPlayList.splice(evt.newIndex, 0, playList.splice(evt.oldIndex, 1) [0]);
      // Change the playlist order
      dispatch(changePlayListAction(tempPlayList))
    },
  });
}, [playList, dispatch]);
Copy the code
  1. To complete the effect

Store music lists locally

Considering that immutable and Redux-persise are incompatible, the main reason is that immutable is a data format that redux-persist does not recognize, so that the state we want to store in REdux cannot be stored locally. Redux-persist -transform-immutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable mutable

Save all song ids in the song list to the local Storage

Default Song List

In fact, we only need to know the song ID each time we request the song, so we only need to store the song ID locally when the first initialization, but we need to delete the song ID stored locally (duplicate song ID will not be stored locally).

Implementation effect

Song order (asynchronous problem)

One small problem: as we traverse the song list array network id send request, the network due to send the request is asynchronous, lead to our list of music songs order is not in accordance with good order sending arrays and is there a way to only the last request is successful before sending the network request?

The answer is yes, first think of the promise partner plus chicken leg 🍗, of course you can also use async await

Train of thought

(1) Solution: Promise + setInterval (timer) (2) Some students may ask, why use timers? (3) This is because when we send Ajax, we can't control it very well. We use an identifier variable to control whether ajax is sent or not (default is true). (4) Every time we start the timer, First check whether the identity variable is true and send Ajax if it is true. Set the identity variable to false during the ajax request (that is, no network request will be sent in the timer). When the Ajax request is complete (that is, when the asynchronous operation succeeds), change the identity variable to True so that you have good control. To sum up, the next Ajax request can only be made when the current Ajax request is successfully controlled. (The core is to use identity variables to control the Ajax request, and only the last Ajax request is successful, the next Ajax request can be made.)Copy the code

code

export const getSongDetailArrayAction = (listId) = > {
  return (dispatch, getState) = > {
    // 1. Get the list of songs
    const playList = getState().getIn(['player'.'playList'])
    let i = 0
    let timer = null
    let excuteRun = true / / control ajax
    timer = setInterval(() = > {
      let idx = listId[i]
      new Promise((resolve, reject) = > {
        excuteRun &&
          getSongDetail(idx).then((res) = > {
            excuteRun = false
            // console.log(res.songs[0])
            // (0) Add the song ID to the local store
            addPlaylistId(idx)
            const song = res.songs && res.songs[0]
            // console.log(song)
            if(! song)return
            // (1) Add to the playlist
            playList.push(song)
            dispatch(changePlayListAction(playList))
            // (2) Change the current playing index
            const songIndex = playList.length - 1
            dispatch(changeSongIndexAction(songIndex))
            // (3) Change the current playing song
            dispatch(changeCurrentSongAction(song))
            // (4) Request the lyrics of the song
            dispatch(getLyricAction(idx))
            // (5) Update the number of songs
            dispatch(changePlayListCount(playList.length))
            resolve(i)
          })
      }).then((value) = > {
        excuteRun = true
      })
      i++
      if (i >= listId.length) {
        clearInterval(timer)
      }
    })
  }
}
Copy the code

The effect

  • No matter how many times we refresh it, it will follow the list of songs in our local storeidArray order is requested

In order to optimize

  • Support for memorizing song lists
    • After refreshing the page, the music playlist can remember the order in which it was last played
  • Remember the music that plays before closing the page
    • After refreshing the page, the current song is remembered before closing the page. When opening the page again, the default song is the song played before closing

Now that we have completed the basic functions of the “netease Cloud Music PC”, I believe you are familiar with the React family bucket. Next, you can supplement and improve the functions by yourself.

If there is any part of the article do not understand or write bad or have any suggestions are welcome to put forward 🤗, I hope to make progress together with you;

Thank you

  • Thank you very much for Teacher Wang Hongyuan’s React core technology practice, which made me learn a lot of React knowledge.
  • Thanks to the backend provider Binaryify, the interface is stable and the documentation is good