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

雖然全網上 Vue 仿餓了麼、xx音樂的項目一大堆,可是我仍是厚着臉皮來了,畢竟我也稍微標新立異,PC端爲主,移動端爲輔打造的 web 音樂播放器,因此說大佬們關愛下,畢竟我這個播放器剛從韓國回來!!!css

模仿QQ音樂網頁版界面,採用flexbox和position佈局; mmPlayer雖然是響應式,但主要覺得PC端爲主,移動端只作相應適配(未作歌詞顯示); 只作主流瀏覽器兼容(對IE說拜拜並特別優化,想一想之前作項目還要兼容IE7,都是淚啊!!!)html

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

Vue-mmPlayer 源碼地址html5

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

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

如何安裝與使用

mmPlayerios

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

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

npm install //安裝依賴

npm run dev //服務端運行

npm run build  //項目打包
複製代碼

後臺服務器git

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

npm install //安裝依賴

node app.js //服務端運行 訪問 http://localhost:3000
複製代碼

運行mmPlayer後沒法獲取音樂請檢查後臺服務器是否啓動github

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

技術棧

  • 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

相關文章
相關標籤/搜索