Vue全家桶打造自適應 web 音樂播放器

小小茂茂發表於2018-05-22

雖然全網上 Vue 仿餓了麼、xx音樂的專案一大堆,但是我還是厚著臉皮來了,畢竟我也稍微標新立異,PC端為主,移動端為輔打造的 web 音樂播放器,所以說大佬們關愛下,畢竟我這個播放器剛從韓國回來!!!

模仿QQ音樂網頁版介面,採用flexbox和position佈局; mmPlayer雖然是響應式,但主要以為PC端為主,移動端只做相應適配(未做歌詞顯示); 只做主流瀏覽器相容(對IE說拜拜並特別優化,想想以前做專案還要相容IE7,都是淚啊!!!)

api:一個開源的網易雲音樂 NodeJS 版 API(有 api 才有動力寫!!!)

Vue-mmPlayer 原始碼地址

線上演示地址 伺服器脆弱,小哥哥小姐姐要溫柔對待哦(最好是 PC 瀏覽哦)

桌面版下載  有點簡陋,別介意,主要人懶還有就是沒空

如何安裝與使用

mmPlayer

git clone https://github.com/maomao1996/Vue-mmPlayer.git  //下載mmPlayer

cd mmPlayer //進入mmPlayer播放器目錄

npm install //安裝依賴

npm run dev //服務端執行

npm run build  //專案打包
複製程式碼

後臺伺服器

cd mmPlayer/server //進入後臺伺服器目錄

npm install //安裝依賴

node app.js //服務端執行 訪問 http://localhost:3000
複製程式碼

執行mmPlayer後無法獲取音樂請檢查後臺伺服器是否啟動

api目錄下music的url地址要和後臺伺服器地址一致

技術棧

  • Vue-Cli(Vue 腳手架工具)
  • Vue(核心框架)
  • Vue-Router(頁面路由)
  • Vuex(狀態管理)
  • ES 6 / 7 (JavaScript 語言的下一代標準)
  • Less(CSS前處理器)
  • Axios(網路請求)
  • FastClick(解決移動端300ms點選延遲)

介面欣賞

PC端介面自我感覺還行, 就是移動端介面總覺得怪怪的,奈何審美有限,所以又去整了高仿網易雲的 React 版本(如果小哥哥、小姐姐們有好看的介面,歡迎交流哈)

PC

正在播放

正在播放

排行榜

排行榜

搜尋

搜尋

我的歌單

我的歌單

我聽過的

我聽過的

歌曲評論

歌曲評論

移動端

移動端一
移動端二

功能

播放器、快捷鍵操作、歌詞滾動、正在播放、排行榜、歌單詳情、搜尋、播放歷史、檢視評論、同步網易雲歌單

播放器(核心)

播放器功能其實也就那樣,呼叫 HTML5 音訊的方法、屬性和事件,網上各種文章也都介紹爛了,但是騙贊要有誠意

我實現的功能有這些:上一曲、下一曲、暫停、播放、單曲迴圈、列表迴圈、隨機播放、順序播放、進度條、音量控制

在介紹這些功能之前先理理思路,這裡用個小 demo 介紹,畢竟沒有程式碼,蝦扯蛋誰不會啊,先上程式碼

<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Audio</title>
	<script src="https://cdn.jsdelivr.net/npm/vue@2.5.16/dist/vue.js"></script>
</head>
<body>
	<div id="Audio">
		<audio ref="mmAudio" :src="src" controls></audio>
		<button @click="prev">上一曲</button>
		<button @click="play">暫停/播放</button>
		<button @click="next">下一曲</button>
	</div>
	<script>
		const vm = new Vue({
			el: '#Audio',
			data: {
				list: [
					'https://music.163.com/song/media/outer/url?id=450424527.mp3',
					'https://music.163.com/song/media/outer/url?id=557581284.mp3',
					'https://music.163.com/song/media/outer/url?id=452986458.mp3'
				],//歌曲陣列
				index: 0,//當前歌曲下標
			},
			computed: {
				src() {
					return this.list[this.index] // 當前播放歌曲
				}
			},
			methods: {
				prev() {//上一曲
					let index = this.index - 1;
					if (index < 0) {
						index = this.list.length - 1
					}
					this.index = index;
					this.$nextTick(() => this.$refs.mmAudio.play())
				},
				play() {//暫停/播放
					this.$nextTick(() => this.$refs.mmAudio.paused ? this.$refs.mmAudio.play() : this.$refs.mmAudio.pause())
				},
				next() {//下一曲
					let index = this.index + 1;
					if (index === this.list.length) {
						index = 0
					}
					this.index = index;
					this.$nextTick(() => this.$refs.mmAudio.play())
				}
			}
		})
	</script>
</body>
</html>
複製程式碼

這段程式碼的邏輯非常簡單,我們會新增一個 computed 動態生成 歌曲 src ,當點選暫停/播放的時候,會呼叫 play 方法,修改 播放狀態;當點選上一曲或者下一曲的時候,會修改當前歌曲播放的 index ,然後會觸發 computed 修改 src 然後呼叫 play 方法播放音樂

看完這個小 demo 這些功能都好理解了

上一曲/下一曲:修改當前歌曲播放的 index ,然後會觸發 computed 修改 src ,然後呼叫 play 方法播放音樂

暫停/播放:通過 Audio 的 paused 屬性判斷音訊是否處於暫停狀態,如果返回 true 呼叫 play 播放音樂,如果返回 false 呼叫 paused 暫停音樂

單曲迴圈:呼叫 Audio 的 ended 事件,在當前歌曲播放結束後將 currentTime 屬性重置為 0

列表迴圈:呼叫 Audio 的 ended 事件,在其回撥中呼叫下一曲方法

隨機播放:通過一個方法打亂歌曲陣列,打亂陣列前先用一個陣列存放原始歌曲陣列

順序播放:呼叫 Audio 的 ended 事件,判斷當前歌曲下標是否和歌曲陣列長度 -1 相等,如果相等就不再呼叫下一曲方法

進度條/音量控制:使用自己封裝的 progress 元件 來進行拖動,點選操作來修改對應的播放進度 currentTime 和音量 volume 小記:在 progress 的事件繫結中只有滑鼠按下mousedown和觸控開始事件 touchstart 是繫結在對應的 DOM 節點上,其他滑鼠移動mousemove和觸控移動touchmove、滑鼠釋放mouseup和觸控釋放touchend等事件繫結的 DOM 都是 document ,不然會出現各種掉鏈子的問題,比如拖動過程中不小心焦點不在對應的 DOM 上了就會中斷拖動

快捷鍵操作

上一曲 Ctrl + Left

播放暫停 Ctrl + Space

下一曲 Ctrl + Right

切換播放模式 Ctrl + O

音量加 Ctrl + Up

音量減 Ctrl + Down

歌詞滾動

歌詞滾動原理:根據當前音樂的播放時間 audio.currentTime 去匹配歌詞 JSON 資料的時間,然後匹配後的歌詞居中顯示並高亮

先來張歌詞 JSON 的迷人玉照給各位小哥哥、小姐姐們解解饞

{
lyric: "[by:魚丸啊魚丸QAQ] [00:00.00] 作曲 : willen [00:01.00] 作詞 : 口袋易百 [00:04.60]伴唱:willen [00:05.10]混音/母帶:willen [00:55.37]外婆的話 還記得嗎 [00:59.01]慈祥的笑容伴我長大 [01:02.75]每當庭院開滿了桂花 [01:06.50]淡淡花香都是愛的牽掛 [01:10.30]外婆的話 還記得嗎 [01:14.01]受傷的孩子別忘了回家 [01:17.66]夕陽西下 歲月染白了發 "
}
複製程式碼

由於 audio.currentTime 是以秒計,而歌詞 JSON 的格式是醬樣子的 [00:00.00] 所以我們要先把歌詞 JSON 化個妝

// 這是化妝過程,具體流程我就不多說了,畢竟我是厚著臉皮來掘金騙小心心的
 function parseLyric(lrc) {
    let lyrics = lrc.split("\n");
    let lrcObj = [];
    for (let i = 0; i < lyrics.length; i++) {
        let lyric = decodeURIComponent(lyrics[i]);
        let timeReg = /\[\d*:\d*((\.|\:)\d*)*\]/g;
        let timeRegExpArr = lyric.match(timeReg);
        if (!timeRegExpArr) continue;
        let clause = lyric.replace(timeReg, '');
        for (let k = 0, h = timeRegExpArr.length; k < h; k++) {
            let t = timeRegExpArr[k];
            let min = Number(String(t.match(/\[\d*/i)).slice(1)),
                sec = Number(String(t.match(/\:\d*/i)).slice(1));
            let time = min * 60 + sec;
            if (clause !== '') {
                lrcObj.push({time: time, text: clause})
            }
        }
    }
    return lrcObj;
}
複製程式碼

我比較菜,火星文(正則)全靠搜尋引擎,這個是歌詞正則原地址,不過我的稍加修飾了下

當這一切 OK 後就只要匹配時間居中並高亮展示當前歌詞就行啦! 目前我是通過 for 迴圈對比大小找到第一個比當前播放時間大的歌詞時間,但是我一直覺得這樣寫不夠優雅,無奈又想不到其他方法,希望知道優雅方法的小哥哥、小姐姐來指點迷津

正在播放

顯示和管理當前播放的歌單,可以清空當前播放器列表、刪除置頂歌曲,修改歌曲的播放狀態

排行榜

呼叫對應 API 介面獲取網易雲音樂的排行榜列表(目前沒做圖片懶載入)

歌單詳情

傳入歌單 ID 呼叫對應 API 介面獲取當前歌單下所有歌曲,由於是獲取所有歌曲在移動端滑動時會有所卡頓,這個後期會加入Better-Scroll(一款重點解決移動端各種滾動場景需求的外掛)

搜尋

目前只實現了歌曲的搜尋,後續會完善 專輯 / 歌手 / 歌單 / 使用者 的搜尋 通過搜尋關鍵字請求 API 獲取搜尋資料並顯示歌曲 分頁:呼叫 scroll 事件,滾動到底部下載下一頁,目前是50條每頁,當所有資料請求完畢後會提示:沒有更多歌曲啦!

在上次網易雲音樂和 QQ 音樂版權之爭中,周杰倫的所有單曲全部 GG ,然後我就在播放事件中先去請求當前歌曲的 url ,如果沒有就會提示:當前歌曲無法播放;如果不做這個,萬一又被懟那就不好了,畢竟使用者是大佬,惹不起也躲不起

播放歷史

呼叫 canplay 事件,將不會播放出錯的歌曲通過 localStorage 儲存 PS:一開始我是通過 play 事件 ,結果不管你能不能放都會加入播放歷史,然後被吐槽了,最後各種研究發現 canplay 更優雅

檢視評論

這個是段子云音樂的一大亮點,必須要加上 通過當前播放音樂的 id 呼叫對應的 API 介面 分別展示熱門評論和最新評論 當時做這個的時候介面簡直小意思,但是評論時間簡直鬱悶,有:

剛剛 / XX 分鐘前 / XX:XX / XX 月 XX 日 / XX 年 XX 月 XX 日

大概花了半個多小時才 KO 掉,不過不知道為啥一直覺得我這麼寫不夠優雅,希望知道優雅方法的小哥哥、小姐姐來指點迷津

同步網易雲歌單

先去 網易雲音樂 獲取自己的 UID 然後通過呼叫對應的 API 介面 獲取該使用者的歌單,然後傳入歌單 ID 獲取歌單詳情。

當對應的 UID 返回的 playlist 陣列長度為 0 時提示 未查詢找UID為 ${uid} 的使用者資訊

登陸成功後呼叫 localStorage 儲存當前 UID ,下次開啟時會先讀取本地儲存的 UID 進行登入操作

退出登入時清空 localStorage ,以免下次開啟時還會登入

後續

  1. 程式碼提高複用率
  2. 優化移動端介面和體驗,比如 Better-Scroll圖片懶載入
  3. 專輯 / 歌手 / 歌單 / 使用者 的搜尋
  4. koa 重構後臺服務
  5. 完善下桌面版的體驗(畢竟太簡陋,自己都看不下去了)
  6. ...(腦容量不夠,暫時就想到這些)

感謝

HTML 音訊/視訊 DOM 參考手冊

網易雲音樂 NodeJS 版 API

Vue.js 升級踩坑小記

Lodash(JavaScript 實用工具庫)

其他

個人練手專案,主要有段時間閒得無聊,然後在逛 Gayhub 時發現個開源的音樂API —— 網易雲音樂 NodeJS 版 API 最後就一邊無恥的水群一邊找好看的介面順帶整理下開發思路

曾經有段時間很多人問我用的什麼什麼 UI 框架,所以我另外再提一下,該專案基礎 UI 全是個人結合專案和各大 UI 框架程式碼風格慢慢敲的,再推薦個 Vue 課程 —— Vue.js 音樂 App 高階實戰課程

還有就是有木有 React 大佬帶我,最近正在自學中,有很多迷津求解答 這是一邊學一邊做的專案 React移動端版本(高仿網易雲音樂 自我感覺這高仿沒毛病

最後我們切入主題,歡迎小哥哥、小姐姐們給我點 "Star" "Fork"(地址在這裡 Vue-mmPlayer 原始碼地址),畢竟第一次發文騙贊(微微一笑),小哥哥、小姐姐們給點鼓勵。

如有問題請在本文回覆或者直接在 Issues 中提,或者您發現問題並有非常好的解決方案,歡迎 PR

相關文章