前言
本功能是基于 vue3 + ts 实现的。之所以选择网易云作为练手项目,主要是因为他的API是开源的,相对齐全。
网易云API地址:binaryify.github.io/NeteaseClou…
先上效果图
一. 开发步骤
1. 歌单实现逻辑
1.1 首先获取歌单id(这里我拿的是推荐歌单:/personalized)
推荐歌单
说明 : 调用此接口 , 可获取推荐歌单可选参数 : limit: 取出数量 , 默认为 30 (不支持 offset)
接口地址 : /personalized
调用例子 : /personalized?limit=1
接口返回值:(接口返回值太多了,就此省略。大家可以用postman请求查看)
1.2 获取歌单详情
获取歌单详情
说明 : 歌单能看到歌单名字, 但看不到具体歌单内容 , 调用此接口 , 传入歌单 id, 可 以获取对应歌单内的所有的音乐(未登录状态只能获取不完整的歌单,登录后是完整的),但是返回的trackIds是完整的,tracks 则是不完整的,可拿全部 trackIds 请求一次 song/detail 接口获取所有歌曲的详情 (github.com/Binaryify/N…)必选参数 : id : 歌单 id
可选参数 : s : 歌单最近的 s 个收藏者,默认为8
接口地址 : /playlist/detail
调用例子 : /playlist/detail?id=24381616
注意!!!
这个接口返回的仅仅是歌单部分内容,并不包含歌曲url – 播放地址(即mp3)。因此还需要额外请求一个获取音乐url的接口。
如果想要完整的歌单,就先拿接口返回的trackIds再去请求song/detail。(这里就不一一说明了)
1.3 获取音乐url
获取音乐 url
说明 : 使用歌单详情接口后 , 能得到的音乐的 id, 但不能得到的音乐 url, 调用此接口, 传入的音乐 id( 可多个 , 用逗号隔开 ), 可以获取对应的音乐的 url,未登录状态或者非会员返回试听片段(返回字段包含被截取的正常歌曲的开始时间和结束时间)必选参数 : id : 音乐 id
可选参数 : br: 码率,默认设置了 999000 即最大码率,如果要 320k 则可设置为 320000,其他类推
接口地址 : /song/url
调用例子 : /song/url?id=33894312 /song/url?id=405998841,33894312
拿到音乐url后就可以调用HTML audio元素实现音频播放啦。(具体往下看)
这里总结下:
先获取 歌单id -> 然后获取 歌曲id -> 最后获取 音频
反过来就是,要拿音频地址就要先获取歌曲id,所以你能拿到歌曲id的话,歌单获取这步就可以省略了。
2. 播放音频逻辑实现
好啦,歌单逻辑说完了。接下来就是讲如何实现播放了。
2.1 使用audio实现
一般来说,直接
<audio src="音频地址" controls />
这样就已经能实现一个音频播放了。但如果要自定义样式的话,就不需要加controls(设置或返回音频是否应该显示控件(比如播放/暂停等))。那么就要自己做上一首播放,下一首播放,暂停播放,开始播放等功能了。
实现一个简单的音频播放器,首先要了解下audio的一些属性和方法。这里我就先列举几个等下要用到的。
具体可以看 www.w3school.com.cn/jsref/dom_o…
Audio 对象属性
属性 | 概述 |
---|---|
paused | 设置或返回音频是否暂停。 |
src | 设置或返回音频的 src 属性的值。 |
duration | 返回音频的长度(以秒计)。 |
controls | 设置或返回音频是否应该显示控件(比如播放/暂停等)。 |
ended | 返回音频的播放是否已结束。 |
Audio 对象方法
方法 | 概述 |
---|---|
play() | 开始播放音频。 |
pause() | 暂停当前播放的音频。 |
canplay() | 当浏览器能够开始播放指定的音频/视频时,会发生 canplay 事件。 |
timeupdate() | timeupdate 事件在音频(audio)的播放位置发生改变时触发。 |
2.2 实现Audio Controls功能
一个简易的音乐播放器,一共分为四大功能:上一首播放、下一首播放、暂停播放、开始播放。
需要你们自己加上控制按钮,然后绑定相关事件。如图:
HTML
<audio
ref="audio"
:src="currentPlayUrl"
@canplay="getDuration"
@pause="pause"
@timeupdate="timeupdate"
@play="play"
/>
开始播放
setup() {
const audio = ref(); // 这里是拿到audio的dom元素
// 开始播放音频
function audioPlay() {
audio.value.play();
};
// dom元素加载完后开始播放音乐
onMounted(() => {
audioPlay();
});
return {
audio
};
}
暂停播放
/**
* 控制播放按钮
* 通过paused属性,判断当前音频播放状态
*/
function controlPlay() {
if(!audio.value.paused) {
audio.value.pause(); // 停止播放
} else {
audio.value.play(); // 开始播放
}
};
改变播放按钮状态
function play() {
// 展示播放按钮
};
function pause() {
// 展示暂停按钮
};
上一首播放、下一首播放
首先要先定义一个歌单列表,然后定义一个当前播放的索引值以及当前播放的url
const state = reactive({
playList: [
{ url: 'http://m7.music.126.net/20210326150405/a91efaab5690d7966eff4f8104ae575e/ymusic/9ba6/4a9a/e903/eaca05cc36e0d64a2cd104722f6f9cc4.mp3' },
{ url: 'http://m7.music.126.net/20210326154148/251d2d32b08419744ca682170d98bf35/ymusic/0409/520c/5158/3c17fbba85efa6b428d2f2dafd5de326.mp3' },
{ url: 'http://m8.music.126.net/20210326162043/b8af89f1ac2579ea17035b51a7656f7f/ymusic/7634/c63c/a0c1/ad330e06c7f3c791d065af5c255e002c.mp3' }
],
currentIndex: 0
});
const currentPlayUrl = computed(() => {
return state.playList[state.currentIndex];
});
/**
* 上一首播放
* 若当前播放索引值 = 0(第一首),则播放歌单最后一首,否则播放上一首
*/
function prevPlay() {
state.currentIndex = state.currentIndex === 0 ? state.playList.length - 1 : state.currentIndex - 1;
// 这里要延迟播放,因为要先让它加载一下
nextTick(() => {
audioPlay();
});
}
/**
* 下一首播放
* 若当前播放索引值 = 歌单列表长度(最后一首),则播放歌单第一首,否则播放下一首
*/
function prevPlay() {
state.currentIndex = state.currentIndex === state.playList.length - 1 ? 0 : state.currentIndex + 1;
nextTick(() => {
audioPlay();
});
}
到这里,功能就讲完啦。剩下的就是歌曲信息的展示啦。关于歌曲信息这块,我就重点说下如何获取音频时长吧。
3. 获取音频时长
注意:获取音频时长主要是靠Audio的duration这个属性获取的。但是如果在音频还未可以播放的时候,是不可以获取到它的时长的。
当音频/视频处于加载过程中时,会依次发生以下事件:
- loadstart
- durationchange
- loadedmetadata
- loadeddata
- progress
- canplay
- canplaythrough
因此要到canplay这一步才能获取到音频时长。
function getDuration() {
// 此时可以拿到音频时长(audio.value.duration);
}
二. 完整代码
注:我这里的数据结构格式都是按照网易云接口的数据格式来的。数据结构格式你们可以自己自定义,重点关注逻辑就好了。
这是最近在做的一个项目,当时做这个也遇到了不少坑。
现在记下坑,希望对你们有帮助。
或许你们有更好的方法,欢迎大家分享嘻嘻~