和我一起写一个音乐播放器,听一首最伟大的作品
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 有两个核心组件,Audio
和 AudioPlaylist
。
使用 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
文件夹中,分别创建两个名为 images
和 music
的文件夹。 导航到 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歌曲会缓存吗下次不联网能不能听