React.js hooks 练习案例-网易云音乐【day4】

成果展示

昨天又玩了一下,把播放歌曲功能做了,现在可以播放歌曲,导航条会跟随歌曲时间前进,也可以拖拽进度条跳到某个节点继续播放,虽然这样对普通开发没有打作用,但可以提高前端对js的控制能力和数据的处理能力。通过这个项目我也多多少少在开发上了点新的认识,希望你们一样。
React.js hooks 练习案例-网易云音乐【day4】_第1张图片

/* 导入组件 */
import React, { memo, useState, useEffect, useRef, useCallback } from 'react';
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
import { NavLink } from 'react-router-dom';
import { Slider } from 'antd';
/* 导入功能 */
import { getSongDetailAction } from '../store/actionCreators';
import { getSizeImage, formatDate, getPlaySong } from '@/utils/format-utils';
/* 导入UI */
import { PlaybarWrapper, Control, PlayInfo, Operator } from './style';

/* 组件:底部播放条 */
export default memo(function RTAppPlayBar() {
  
  /* 组件 state 模块 */
  // hooks:useState 缓存数据 
  const [currentTime, setCurrentTime] = useState(0); // 当前播放时间
  const [progress, setProgress] = useState(0); // 进度条当前位置
  const [isChanging, setIsChanging] = useState(false); // 进度条是否被拖拽
  const [isPlaying, setIsPlaying] = useState(false); // 进度条是否被拖拽

  /* 共享 state 模块 */
  // 使用 redux-hooks:useSelector 获取共享数据-当前播放歌曲
  const { currentSong } = useSelector(state => ({
    currentSong: state.getIn(["player", "currentSong"])
  }), shallowEqual); // 共享数据浅对比,改变则重绘

   /* 默认参数模块 */
   const picUrl = (currentSong.al && currentSong.al.picUrl) || ""; // 歌手图像url
   const singerName = (currentSong.ar && currentSong.ar[0].name) || "未知歌手"; // 歌手名称
   const duration = currentSong.dt || 0; // 歌曲总时长(秒)
   const showDuration = formatDate(duration, "mm:ss"); // 显示歌曲总时长
   const showCurrentTime = formatDate(currentTime, "mm:ss"); // 显示当前播放时间

  /* 功能模块 */
  // 使用 redux-hooks:useDispatch 获取 dispatch
  const dispatch = useDispatch();

  // 使用 hooks:useEffect 函数挂载后执行
  // 获取播放歌曲明细请求接口
  useEffect(() => {
    dispatch(getSongDetailAction(167876))
  }, [dispatch])

  // 根据id请求歌曲mp3文件
  useEffect(() => {
    audioRef.current.src = getPlaySong(currentSong.id);
  }, [currentSong])

  // 操作播放器 DOM
  const audioRef = useRef(); 

  // 播放功能
  const playMpusic = useCallback(() => {
    isPlaying ? audioRef.current.pause() : audioRef.current.play(); // true:播放 false:暂停
    setIsPlaying(!isPlaying);
  },[isPlaying])

  // 时间更新功能
  const tiemUpdate = (e) => {
    if (!isChanging) { // 进度条没被拖拽时更新
      setCurrentTime(e.target.currentTime * 1000); // 设置当前播放时间
      setProgress(currentTime / duration * 100); // 当进度条没有被拖动时更新进度条当前位置
    }
  }

  // 当函数传入子组件时,父组件重绘函数也会被重新生成,新的函数与旧函数地址不一致,子组件也会触发重绘。
  // 使用 hooks:useCallback 包裹,会将函数保存到缓存,父组件重绘后返回同一个函数,则不会引发子组件重绘提高性能
  // 拖动进度条改变事件
  const sliderChange = useCallback((value) => {
    setIsChanging(true); // 设置进度条正在被拖拽
    const currentTime = value / 100 * duration / 1000; // 计算当前播放时间
    setCurrentTime(currentTime * 1000); // 设置当前播放时间
    setProgress(value); // 设置进度条当前位置
  }, [duration]); // 歌曲总时长改变则重绘

  // 鼠标放开进度条改变事件
  const sliderAfterChange = useCallback((value) => {
    const currentTime = value / 100 * duration / 1000; // 计算当前播放时间
    setCurrentTime(currentTime * 1000); // 设置当前播放时间
    audioRef.current.currentTime = currentTime; // 设置进度条当前位置与歌曲播放位置
    setIsChanging(false); // 设置进度条没被拖拽
    if(!isPlaying) playMpusic();
  }, [duration, isPlaying, playMpusic]); // 歌曲总时长改变则重绘


  /* UI布局模块 */
  return (
    
      
{currentSong.name} {singerName}
{showCurrentTime} / {showDuration}
) })

你可能感兴趣的:(react,hooks)