返回

让音乐响起!手把手构建Web音乐App——排行榜和歌曲本地持久化

前端

前言

在上一节中,我们使用Redux管理歌曲相关数据,实现了核心播放功能。播放功能是本项目最复杂的一个功能,涉及各个组件之间的数据交互和播放逻辑控制。在这一节中,我们将继续开发排行榜列表和排行榜详情,以及把播放歌曲和播放歌曲列表的持久化到本地。

步入主题

首先,使用chrome浏览器切换到手机模式,输入QQ音乐移动端网址,进入排行榜页面。

分析排行榜页面,可以发现它由两个部分组成:排行榜列表和排行榜详情。排行榜列表显示了各个排行榜的名称和封面,排行榜详情显示了该排行榜下的歌曲列表。

排行榜列表

使用React构建排行榜列表,可以参考如下代码:

import React, { useState } from "react";
import { Link } from "react-router-dom";

const RankingList = () => {
  const [rankings, setRankings] = useState([
    {
      id: 1,
      name: "飙升榜",
      cover: "https://i.loli.net/2021/02/07/T8k4N3ruBMjQ69Y.png",
    },
    {
      id: 2,
      name: "新歌榜",
      cover: "https://i.loli.net/2021/02/07/7WhZogUEC3siVmK.png",
    },
    {
      id: 3,
      name: "原创榜",
      cover: "https://i.loli.net/2021/02/07/9DzGXCtY8Lj5ONe.png",
    },
  ]);

  return (
    <div className="ranking-list">
      {rankings.map((ranking) => (
        <Link to={`/ranking/${ranking.id}`} key={ranking.id}>
          <div className="ranking-item">
            <img src={ranking.cover} alt={ranking.name} />
            <p>{ranking.name}</p>
          </div>
        </Link>
      ))}
    </div>
  );
};

export default RankingList;

排行榜详情

使用React构建排行榜详情,可以参考如下代码:

import React, { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
import { useDispatch, useSelector } from "react-redux";
import { getRankingSongs } from "../redux/actions";

const RankingDetail = () => {
  const { id } = useParams();
  const dispatch = useDispatch();
  const rankingSongs = useSelector((state) => state.rankingSongs);

  useEffect(() => {
    dispatch(getRankingSongs(id));
  }, [dispatch, id]);

  return (
    <div className="ranking-detail">
      <h2>{rankingSongs.name}</h2>
      <ul className="song-list">
        {rankingSongs.songs.map((song) => (
          <li key={song.id}>
            <p>{song.name}</p>
            <p>{song.artist}</p>
          </li>
        ))}
      </ul>
    </div>
  );
};

export default RankingDetail;

歌曲本地持久化

使用Redux实现歌曲播放和歌曲列表的本地持久化,可以参考如下代码:

// 在store中创建reducer
const playerReducer = (state = initialState, action) => {
  switch (action.type) {
    case "SET_PLAYING_SONG":
      return {
        ...state,
        playingSong: action.payload,
      };
    case "SET_PLAYING_LIST":
      return {
        ...state,
        playingList: action.payload,
      };
    default:
      return state;
  }
};

// 在store中注册reducer
const store = createStore(rootReducer);

// 在组件中使用Redux
const Player = () => {
  const dispatch = useDispatch();
  const playingSong = useSelector((state) => state.player.playingSong);
  const playingList = useSelector((state) => state.player.playingList);

  const handlePlaySong = (song) => {
    dispatch({ type: "SET_PLAYING_SONG", payload: song });
    dispatch({ type: "SET_PLAYING_LIST", payload: [song] });
  };

  return (
    <div className="player">
      <p>正在播放:{playingSong ? playingSong.name : ""}</p>
      <ul className="song-list">
        {playingList.map((song) => (
          <li key={song.id}>
            <p>{song.name}</p>
            <button onClick={() => handlePlaySong(song)}>播放</button>
          </li>
        ))}
      </ul>
    </div>
  );
};

结语

这一节,我们完成了排行榜列表、排行榜详情和歌曲本地持久化的功能。这些功能进一步完善了我们的Web音乐App,使它更加实用和易用。在下一篇博文中,我们将继续深入讲解如何构建歌曲搜索功能和用户登录注册功能,敬请期待。