实现网易云播放器

前言

本功能是基于 vue3 + ts 实现的。之所以选择网易云作为练手项目,主要是因为他的API是开源的,相对齐全。
网易云API地址:binaryify.github.io/NeteaseClou…

先上效果图

player.gif

一. 开发步骤

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功能

一个简易的音乐播放器,一共分为四大功能:上一首播放、下一首播放、暂停播放、开始播放。
需要你们自己加上控制按钮,然后绑定相关事件。如图:

image.png

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这个属性获取的。但是如果在音频还未可以播放的时候,是不可以获取到它的时长的。

当音频/视频处于加载过程中时,会依次发生以下事件:

  1. loadstart
  2. durationchange
  3. loadedmetadata
  4. loadeddata
  5. progress
  6. canplay
  7. canplaythrough

因此要到canplay这一步才能获取到音频时长。

function getDuration() {
    // 此时可以拿到音频时长(audio.value.duration);
}
 

二. 完整代码

注:我这里的数据结构格式都是按照网易云接口的数据格式来的。数据结构格式你们可以自己自定义,重点关注逻辑就好了。

这是最近在做的一个项目,当时做这个也遇到了不少坑。
现在记下坑,希望对你们有帮助。
或许你们有更好的方法,欢迎大家分享嘻嘻~

(0)
上一篇 2021年3月27日 上午8:45
下一篇 2021年3月27日 上午9:00

相关推荐

发表回复

登录后才能评论