和我一起写一个音乐播放器,听一首最伟大的作品

Posted 前端修罗场

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了和我一起写一个音乐播放器,听一首最伟大的作品相关的知识,希望对你有一定的参考价值。

⭐️ 本文首发自 前端修罗场(点击加入),是一个由 资深开发者 独立运行 的专业技术社区,我专注 Web 技术、Web3、区块链、答疑解惑、面试辅导以及职业发展现在加入,私聊我即可获取一次免费的模拟面试机会,帮你评估知识点的掌握程度,获得更全面的学习指导意见,交个朋友,少走弯路,少吃亏!

网上都在说仿一个网易云什么的,能不能高级一点点(因为听不了JAY 的歌啊)!!!在本文中,我们将使用 React 和 ts-audio 仿造流行音乐流媒体服务 Spotify 构建一个类似的音乐播放器。让你构建一个音乐播放器简单又快速!

因为 Spotify 未提供公共的音乐资源 API,所以我们将会使用一组虚拟数据。 话不多说,我们开始~

什么是 ts-audio?

ts-audio 是一个能够使 AudioContext API 更易于交互的第三方库。 它能为开发者提供播放、暂停等方法,并允许你创建播放列表。 总的来说,ts-audio 提供以下功能与特征:

  • 一个简单的 API,它抽象了 AudioContext API 的复杂性
  • 提供跨浏览器支持
  • 轻松创建音频播放列表
  • 适用于任何能够编译成 javascript 的语言

开始使用 ts-audio 构建

让我们首先使用以下命令创建一个新的 React 应用程序:

npx create-react-app ts-audio
// or
yarn create react-app ts-audio

接下来,我们安装 ts-audio 包:

yarn add ts-audio

ts-audio 有两个核心组件,AudioAudioPlaylist

使用 Audio 组件

Audio 组件允许我们传入要播放的一首歌曲。 它还为我们提供了某些方法,例如 play()、pause()、stop() 等等。打开 App.js 填入如下内容:

// App.js

import Audio from 'ts-audio';
import GreatestWorkOfArt from './music/GreatestWorkOfArt.mp3';

export default function App() 
  const audio = Audio(
    file: GreatestWorkOfArt
  )

  const play = () => 
    audio.play()
  

    const pause = () => 
    audio.pause()
  

    const stop = () => 
    audio.stop()
  

  return (
    <>
      <button onClick=play>Play</button>
      <button onClick=pause>Pause</button>
      <button onClick=stop>Stop</button>
    </>
  )

在上面的代码块中,我们从 ts-audio 导入了 Audio 组件和我们想要播放的歌曲——最伟大的作品(此处必须拥有名字)。 接着,我们创建了一个音频实例 audio,将其设置为导入的 Audio 组件,然后将导入的音乐传递给 Audio 元素暴露出来的 file 参数。

后面的代码中,我们利用了 ts-audio 提供给的方法,比如 play() 和 pause(),通过按钮上绑定的点击事件函数调用它们。

使用 AudioPlaylist 组件

AudioPlaylist 组件允许我们传入多首歌曲,但它们必须在一个数组中,否则 ts-audio 不会播放它们。 AudioPlaylist 组件为我们提供了 play()、pause()、stop()、next() 和 prev() 等方法。

下面的代码块解释了如何使用 AudioPlaylist 组件:

// App.js

import  AudioPlaylist  from 'ts-audio';
import GreatestWorkOfArt from './music/GreatestWorkOfArt.mp3';
import Mojito from './music/Mojito.mp3';

export default function App() 
  const playlist = AudioPlaylist(
    files: [GreatestWorkOfArt, Mojito]
  )

  const play = () => 
    playlist.play()
  

  const pause = () => 
    playlist.pause()
  

  const next = () => 
    playlist.next()
  

  const previous = () => 
    playlist.prev()
  

  const stop = () => 
    playlist.stop()
  

  return (
    <>
      <button onClick=play>Play</button>
      <button onClick=pause>Pause</button>
      <button onClick=next>Next</button>
      <button onClick=prev>Prev</button>
      <button onClick=stop>Stop</button>
    </>
  )

除了播放多首歌曲之前,我们的音乐播放器还应该具备以下功能:

  • 每当我们单击下一个或上一个时,会将艺术家更改为当前歌曲的艺术家
  • 将图像更改为当前歌曲的图像
  • 将歌曲名称更改为当前歌曲

接下来,让我们来实现上述功能。

src 文件夹中,分别创建两个名为 imagesmusic 的文件夹。 导航到 images 文件夹并粘贴你可能需要的任何照片。 同样,在 music 文件夹中,你可以粘贴要使用的任何音频文件。

接下来,将歌曲和图片导入到 App.js 中,如下所示:

import  AudioPlaylist  from 'ts-audio';

// Music import
import Intro from './music/Intro.mp3';
import GreatestWorkOfArt from './music/GreatestWorkOfArt.mp3';
import Mojito from './music/Mojito.mp3';
import StillWandering from './music/StillWandering.mp3';
import DontCry from './music/Say goodbye not to cry.mp3';
import PinkOcean from './music/Pink ocean.mp3';
import Reflection from './music/Reflection.mp3';

// Pictures import
import picture1 from './images/picture1.jpeg';
import picture2 from './images/picture2.jpeg';
import picture3 from './images/picture3.jpeg';
import picture4 from './images/picture4.jpeg';
import picture5 from './images/picture5.jpeg';
import picture6 from './images/picture6.jpeg';
import picture7 from './images/picture7.jpeg';


export default function App() 
  const songs =  [
      
        title: 'Intro,
        artist: 'Jay',
        img_src: picture1,
        src: Intro,
      ,
      
        title: '最伟大的作品',
        artist: 'Jay',
        img_src: picture2,
        src: GreatestWorkOfArt,
      ,
      
        title: 'Mojito',
        artist: 'Jay',
        img_src: picture3,
        src: Mojito,
      ,
      
        title: '还在流浪',
        artist: 'Jay',
        img_src: picture4,
        src: StillWandering,
      ,
      
        title: '说好不哭',
        artist: 'Jay',
        img_src: picture5,
        src: DontCry,
      ,
      
        title: '粉色海洋',
        artist: 'Jay',
        img_src: picture6,
        src: PinkOcean,
      ,
      
        title: '倒影',
        artist: 'Jay',
        img_src: picture7,
        src: Reflection,
      ,
    ]

  const playlist = AudioPlaylist(
      files: songs.map((song) => song.src),
    );

  const handlePlay = () => 
    playlist.play();
  ;

  const handlePause = () => 
    playlist.pause();
  ;

  const handleSkip = () => 
    playlist.next();
  ;

  const handlePrevious = () => 
    playlist.prev();
  ;

  return (
    <>
      <button onClick=handlePlay>Play</button>
      <button onClick=handlePause>Pause</button>
      <button onClick=handleSkip>Next</button>
      <button onClick=handlePrevious>Prev</button>     
    </>
  );

在上面的代码块中,我们导入了歌曲和图像。 接下来,我们创建了一个包含对象的歌曲数组。 每个对象都有一个标题、艺术家、导入图像的 img_src 和导入歌曲的 src

之后,我们通过歌曲数组映射到歌曲的 src,我们将其传递给 files 参数。 请记住,我们必须将它作为一个数组传入,然后 map() 方法通过调用一个函数来生成一个新的数组。

我们还创建了我们的方法并将它们传递给各种按钮。 我们将创建一个 Player.js 文件来处理按钮的逻辑,用于处理 App.js 中的功能:

// Player.js
export default function Player( play, pause, next, prev ) 
  return (
    <div className="c-player--controls">
      <button onClick=play>Play</button>
      <button onClick=pause>Pause</button>
      <button onClick=next>Next</button>
      <button onClick=prev>Previous</button> 
    </div>
  );

在上面的代码块中,我们创建了一个 Player.js 文件,然后捕获来自 App.js 的 props,最后将它们传递给按钮。

创建功能

为了为我们的应用程序创建功能,我们导入 useState 来获取歌曲的当前索引。 然后我们将图像设置为当前照片,将艺术家设置为当前艺术家,将标题设置为当前标题:

// App.js

import React,  useState  from 'react';
import Player from './Player';
import  AudioPlaylist  from 'ts-audio';
// Music import

// Pictures import

export default function App() 
  const [currentSong, setCurrentSong] = useState(0);
  const [isPlaying, setIsPlaying] = useState(false);


  // Songs Array

  const playlist =AudioPlaylist(
      files: songs.map((song) => song.src),
    );

  const handlePlay = () => 
    playlist.play();
    setIsPlaying(true);
  ;

  const handlePause = () => 
    playlist.pause();
    setIsPlaying(false);
  ;

  const handleSkip = () => 
    playlist.next();
    setIsPlaying(true);
    setCurrentSong(
      (currentSong) => (currentSong + 1 + songs.length) % songs.length
    );
  ;

  const handlePrevious = () => 
    playlist.prev();
    setIsPlaying(true);
    setCurrentSong(
      (currentSong) => (currentSong - 1 + songs.length) % songs.length
    );
  ;
  return (
    <>
      <div className="App">
        <div className="c-player">
          <div className="c-player--details">
            ' '
            <div className="details-img">
              ' '
              <img src=songs[currentSong].img_src alt="img" />
            </div>
            <h1 className="details-title">songs[currentSong].title</h1>
            <h2 className="details-artist">songs[currentSong].artist</h2>
          </div>
          <Player
            play=handlePlay
            pause=handlePause
            isPlaying=isPlaying
            setIsPlaying=setIsPlaying
            next=handleSkip
            prev=handlePrevious
          />
        </div>
      </div>
    </>
  );


我们创建了一个 currentSong 状态并将其初始值设置为 0。 当我们单击下一个按钮时,我们将按照如下公式设置 currentSong 状态的值:

currentSong + 1 + songs.length) % songs.length

当我们单击上一个按钮时,我们将按照如下公式设置 currentSong 状态的值:

currentSong - 1 + songs.length) % songs.length

我们还创建了一个 isPlaying 状态来检查歌曲是否正在播放,然后我们将它作为 props 传递给 Player 组件。

最后,我们处理了更改图像、艺术家和歌曲标题的功能。

当我们启动应用程序时,似乎一切正常; 单击“下一步”按钮时图像会发生变化。

但是问题来了,播放的歌曲与屏幕上显示的图片和艺术家姓名不匹配。 有时,同时播放两首或多首歌曲。

下面我们来解决问题。

解决问题

当我们单击下一个或上一个按钮时,我们正在重新计算值并导致重新渲染。

为了阻止这种情况,我们将歌曲数组和创建的播放列表实例包装在 useMemo Hook 中,如下所示:

// App.js

import React,  useState, useMemo  from 'react';
import Player from './Player';
import  AudioPlaylist  from 'ts-audio';
// Music import

// Pictures import

export default function App() 
  const [currentSong, setCurrentSong] = useState(0);

  const songs = useMemo(
    () => [
      
        title: 'Intro,
        artist: 'Jay',
        img_src: picture1,
        src: Intro,
      ,
      
        title: '最伟大的作品',
        artist: 'Jay',
        img_src: picture2,
        src: GreatestWorkOfArt,
      ,
      
        title: 'Mojito',
        artist: 'Jay',
        img_src: picture3,
        src: Mojito,
      ,
      
        title: '还在流浪',
        artist: 'Jay',
        img_src: picture4,
        src: StillWandering,
      ,
      
        title: '说好不哭',
        artist: 'Jay',
        img_src: picture5,
        src: DontCry,
      ,
      
        title: '粉色海洋',
        artist: 'Jay',
        img_src: picture6,
        src: PinkOcean,
      ,
      
        title: '倒影',
        artist: 'Jay',
        img_src: picture7,
        src: Reflection,
      ,
    ],
    []
  );

  const playlist = useMemo(() => 
    return AudioPlaylist(
      files: songs.map((song) => song.src),
    );
  , [songs]);

useMemo Hook 能有效地缓存该值,因此它不需要重新计算,因此不会导致重新渲染。

添加样式

在本文中,我们会使用 Font Awesome Icons 中提供的图标来美化我们的 UI。 你可以使用以下命令安装 Font Awesome 包:

yarn add @fortawesome/fontawesome-svg-core
yarn add @fortawesome/free-solid-svg-icons
yarn add @fortawesome/react-fontawesome

将以下代码复制并粘贴到 Player.js 文件中:

// Player.js

import  FontAwesomeIcon  from '@fortawesome/react-fontawesome';
import  faPlay, faPause, faForward, faBackward  from '@fortawesome/free-solid-svg-icons';
export default function Player( play, pause, next, prev, isPlaying, setIsPlaying ) 
  return (
    <div className="c-player--controls">
      <button className="skip-btn" onClick=prev>
        <FontAwesomeIcon icon=faBackward />
      </button>
      <button
        className="play-btn"
        onClick=() => setIsPlaying(!isPlaying ? play : pause)
      >
        <FontAwesomeIcon icon=isPlaying ? faPause : faPlay />
      </button>
      <button className="skip-btn" onClick=next>
        <FontAwesomeIcon icon=faForward />
      </button>
    </div>
  );

在上面的代码块中,我们从 App.js 文件中获取 props,然后在 Player.js 文件中处理它们。 对于样式,请将以下代码复制并粘贴到你的 index.css 文件中:

* 
  margin: 0;
  padding: 0;
  box-sizing: border-box;
  font-family: 'Fira Sans', sans-serif;

body 
  background-color: #ddd;

.App 
  display: flex;
  align-items: center酷狗音乐vip歌曲会缓存吗下次不联网能不能听

html如何实现多首背景音乐轮流循环播放?

送你的代码上太空,与华为云一起开发“最伟大的作品”

设计模式实战命令模式:原理篇

设计模式实战命令模式:原理篇

设计模式实战命令模式:原理篇