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]如果场景里出现一架钢琴

我们得把这个数据处理一下,转换成这样子的
在这里插入图片描述
在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

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值