天天看點

React實作(Web端)網易雲音樂項目(六),錯過了真的可惜呀

今天實作歌曲播放時,歌詞随着滾動的效果

React實作(Web端)網易雲音樂項目(六),錯過了真的可惜呀

網易雲原本的歌詞是這樣的

[00:00.000] 作曲 : 許嵩
[00:01.000] 作詞 : 許嵩
[00:22.240]天空好想下雨
[00:24.380]我好想住你隔壁
[00:26.810]傻站在你家樓下
[00:29.500]擡起頭數烏雲
[00:31.160]如果場景裡出現一架鋼琴
[00:33.640]我會唱歌給你聽
[00:35.900]哪怕好多盆水往下淋
[00:41.060]夏天快要過去}
[00:31.160]如果場景裡出現一架鋼琴
           

我們得把這個資料處理一下,轉換成這樣子的

React實作(Web端)網易雲音樂項目(六),錯過了真的可惜呀

在utils裡面建立一個lrc-parse.js

const parseExp = /\[(\d{2}):(\d{2})\.(\d{2,3})\]/

export function parseLyric(lyricString) {
  const lineStrings = lyricString.split("\n");
  const lyrics = [];
  for (let line of lineStrings) {
    if (line) {
      const lrcContent = line.replace(parseExp, '').trim();
      const timeResult = parseExp.exec(line);
      const milliseconds = timeResult[3].length === 3 ? timeResult[3] * 1: timeResult[3]*10
      const lrcTime = timeResult[1] * 60 * 1000 + timeResult[2] * 1000 + milliseconds;
      lyrics.push({
        content: lrcContent,
        time: lrcTime
      })
    }
  }
  console.log(lyrics)
  return lyrics;
  
}
           

通過調用這個parseLyric函數,把我們的歌詞數組放進去即可

好了,現在開始準備寫了

一.先把網絡請求部分寫好

player.js

export function getLyric(id) {
  return request({
    url: "/lyric",
    params: {
      id
    }
  })
}
           

二.把我們請求的資料放在redux中

先定義常量constants.js

export const CHANGE_CURRENT_LYRIC_INDEX = "player/CHANGE_CURRENT_LYRIC_INDEX";
           

然後去定義我們的state,reducer.js

import { Map } from 'immutable';

import * as actionTypes from './constants';

const defaultState = Map({
  currentLyrics: [],
  currentLyricIndex: -1
});

function reducer(state = defaultState, action) {
  switch (action.type) {
    case actionTypes.CHANGE_LYRICS:
      return state.set("currentLyrics", action.lyrics);
    case actionTypes.CHANGE_CURRENT_LYRIC_INDEX:
      return state.set("currentLyricIndex", action.index);
  
    default:
      return state;
  }
}

export default reducer;
           

再去actionCreators.js中封裝方法

import * as actionTypes from './constants';
import { getLyric} from '@/services/player';
export const changeCurrentLyricIndexAction = (index) => ({
  type: actionTypes.CHANGE_CURRENT_LYRIC_INDEX,
  index
})
const changLyricListAction = (lyricList) => ({
  type: actionTypes.CHANGE_LYRIC_LIST,
  lyricList
})

export const getLyric = (id) => {
  return dispatch => {
    getLyric(id).then(res => {
      const lyric = res.lrc.lyric;
      const lyricList = parseLyric(lyric);
      dispatch(changLyricListAction(lyricList));
    })
  }
}
           

之後就可以去元件中使用redux中的資料了

index.js

還是分三步
           

第一步,導入配置

import React, { memo, useRef, useEffect } from 'react';
import { useSelector, shallowEqual } from 'react-redux';
import classNames from 'classnames';

import { scrollTo } from "@/utils/ui-helper";

import { PannelWrapper } from './style';
           

scrollTo是我們封裝的一個滾動js,用于歌詞的滾動

export function scrollTo(element, to, duration) {
  if (duration <= 0) return;
  var difference = to - element.scrollTop;
  var perTick = difference / duration * 10;

  setTimeout(function() {
      element.scrollTop = element.scrollTop + perTick;
      if (element.scrollTop === to) return;
      scrollTo(element, to, duration - 10);
  }, 10);
}
           

第二步,邏輯代碼

const { currentLyrics, currentLyricIndex } = useSelector(state => ({
    currentLyrics: state.getIn(["player", "currentLyrics"]),
    currentLyricIndex: state.getIn(["player", "currentLyricIndex"])
  }), shallowEqual);

  // other hooks
  const panelRef = useRef();
  useEffect(() => {
    if (currentLyricIndex > 0 && currentLyricIndex < 3) return;
    scrollTo(panelRef.current, (currentLyricIndex - 3) * 32, 300)
  }, [currentLyricIndex]);
           

第三步,布局

return (
    <PannelWrapper ref={panelRef}>
      <div className="lrc-content">
        {
          currentLyrics.map((item, index) => {
            return (
              <div key={item.time}
                className={classNames("lrc-item", { "active": index === currentLyricIndex })}>
                {item.content}
              </div>
            )
          })
        }
      </div>
    </PannelWrapper>
  )
           

完事了,over

如果有不懂的,可以去我的github上下載下傳完整代碼,做了很多功能

github項目位址:https://github.com/lsh555/WYY-Music