DIY一個本身的音樂播放器

前言:在最近的一個外包項目中包聯盟(PC端)中使用到了video,遇到了好多坑。突發奇想來踩一踩audio的坑?,果真一入深似海,?下面將分享個人DIY之路-Vue音樂播放器。
注:本項目爲開源項目,不能用於商業應用,僅供學習。有問題或建議發我郵箱:hjingren@aliyun.comjavascript

[舒適提示:pc瀏覽f12手機模式最佳,手機建議wifi下訪問]
demo地址: http://hzzly.net/magic-music(因api不穩定,預覽效果不佳,能夠clone項目和api在本地運行)
項目地址: https://github.com/hzzly/MagicMusic
歡迎你們的star啦?~html

先來個預覽:前端

magic-music1

更多預覽:更多vue

?老鐵們,準備發車(技能點):java

?坐好,出發

實現的功能

一、首頁

  • [x] 輪播

  • [x] 個性推薦[流行、古典、輕音樂、流行]

  • [x] 歌曲操做

    • [x] 加入播放列表

    • [ ] 喜歡

    • [ ] 分享

二、底部播放控件

  • [x] 播放

  • [x] 暫停

  • [x] 下一曲

  • [x] 播放進度條

三、播放頁面

  • [x] 上一曲

  • [x] 播放

  • [x] 暫停

  • [x] 下一曲

  • [x] 播放進度條[弧形進度條]

  • [x] 歌詞滾動

  • [x] 播放的歌詞高亮

  • [ ] 播放模式[單曲循環、列表循環、隨機播放]

四、播放列表

  • [x] 播放歌曲高亮

  • [x] 切歌(單擊切歌)

  • [x] 刪歌(點擊右側小X)

  • [ ] 清空播放列表

  • [ ] 本地緩存播放列表

五、排行榜

  • [x] 熱門排行榜

  • [x] 排行榜裏的歌曲(單擊播放)

六、音樂搜索

輸入搜索關鍵詞,點擊放大鏡圖標

  • [x] 單曲(單擊或點擊歌曲操做(...)添加至音樂播放列表,部分音樂會存在版權問題沒法播放)

  • [x] 歌手

  • [x] 專輯

  • [x] 歌單

  • [x] 用戶

  • [x] 本地緩存搜索列表

七、側邊欄

  • [x] 頭像

  • [x] 菜單

    • [x] 我的中心

API

感謝做者把api整理的這麼好(點個贊?)

網易雲音樂 NodeJS 版 API

目錄結構

|——MagicMusic/
|   |——build/more-->
|   |——confg/
|   |——node_modules/
|   |——src/
|   |   |——assets/                 //靜態文件
|   |   |——components/             //公共組件
|   |   |——api/
|   |   |   |——index.js            //axios封裝與api
|   |   |——pages/                  //存放項目頁面
|   |   |   |——classical.vue       //古典歌曲頁面
|   |   |   |——collection.vue      //排行榜
|   |   |   |——home.vue            //首頁
|   |   |   |——light.vue           //輕音樂歌曲頁面
|   |   |   |——login.vue           //登陸頁面
|   |   |   |——popular.vue         //流行歌曲頁面
|   |   |   |——radio.vue           //電臺歌曲頁面
|   |   |   |——rank.vue            //排行榜列表
|   |   |   |——search.vue          //搜索頁
|   |   |   |——user.vue            //用戶
|   |   |——router/                 
|   |   |   |——index.js            //頁面路由
|   |   |——util                    //公用方法
|   |   |——vuex /                  //存放vuex代碼
|   |   |   |——modules /           //數據模塊
|   |   |   |——store.js            //vuex主入口
|   |   |   |——types.js            //vuex的types文件
|   |   |——App.vue                 //父組件
|   |   |——main.js                 //入口文件
|   |——static/
|   |——.babelrc
|   |——.editorconfig
|   |——.gitgnore
|   |——index.html
|   |——package.json
|   |——README.md

開發心得與總結

一、輪播圖

首先感謝做者ShanaMaid/vue-image-scroll開源的代碼,我把代碼copy下來本身進行了一點修改(沒有手指滑動效果),由於這是移動端,少不了的手指滑動切換,因此添加了vue-touch(偷偷告訴你,vue-touch的next分支仍是支持vue2.0的?)。代碼傳送門

<li v-for="(item,index) in image" :class="[move[index]]">
    <v-touch class="vuetouch"
            v-on:swipeleft="nextPic"
            v-on:swiperight="prePic">
        ...
    </v-touch>
</li>

methods: {
    nextPic(event) {
        let temp = this.move.pop()
        this.move.unshift(temp)
    },
    prePic(event) {
        let temp = this.move.shift()
        this.move.push(temp)
    },
}

二、歌曲操做(喜歡,分享,加入播放列表)動畫、播放列表展開與刪除歌曲動畫

Vue提供了transition的封裝組件,在下列情形中,能夠給任何元素和組件添加 entering/leaving 過渡

  • 條件渲染 (使用 v-if)

  • 條件展現 (使用 v-show)

  • 動態組件

  • 組件根節點

<transition name="move">
    <div class="menu" v-show="item.menuShow">
        ...
    </div>
</transition>

<transition-group name="slide" tag="div" class="list-wrapper">
    <div class="item" v-for="(item, index) in listenLists" :key="item">
        ...
    </div>
</transition-group>

transition-group一組過分動畫,這裏有個小坑的,以前看官網列表過渡的栗子,給每一項設置惟一的key值,通常都會用index。因此在作的時候就把index傳給key,結果過渡總是不對,後來換成對應的item就正常了(生無可戀臉)。

三、直線進度條、弧形進度條

西班牙建築大師曾說過:「直線屬於人類,曲線則歸於上帝」。在這裏我大膽的使用了弧形來做爲進度條,(幾大熱門音樂APP貌似尚未弧形進度條?)。

這裏我用到了Vue的綁定內聯樣式

//直線進度條
<div class="progress-bar">
    <div class="play"
        :style="{width: (now / duration).toFixed(3)*100 + '%'}"></div>
</div>

//弧形進度條
//由於用到了弧形,因此我這裏用到了`border-radius`來使它變成一個大圓,而後平移`translateX`居中,其它不要的部分`overflow: hidden`。
//這裏用兩個div來表示進度條,一條固定的進度條,一條慢慢增長。
<div class="process" @click="showToast">
    <div class="line"></div>
    <div class="pro" :style="{transform: `translateX(${translateX}) rotate(${deg*1 + 56.5*((now / size).toFixed(3))}deg)`}"></div>
</div>

四、本地存儲

將一些數據緩存到localStorage,能夠減小Http請求,從而優化頁面加載時間。

在這個項目中首頁歌曲列表以及搜索歷史用到了本地緩存,拿搜索歷史來舉慄:

created() {
    if (!localStorage.searchHistory) {
        let searchHistory = ['前端', '童話鎮', '恰好碰見你']
        localStorage.searchHistory = JSON.stringify(searchHistory)
    } 
},
methods: {
    _search(keywords) {
        //判斷搜索列表中是否已存在
        let searchHistory = JSON.parse(localStorage.searchHistory)
        let find = searchHistory.findIndex((val) => {
            return val === keywords
        })
        find === -1 ? localStorage.searchHistory = JSON.stringify([keywords, ...searchHistory]) : ''
    }
}

五、圖片懶加載

使用了vue-lazyload插件
用法?:

$ npm install vue-lazyload
//main.js
import VueLazyLoad from 'vue-lazyload'
import def_lazy_img from '../static/img/loading.gif' //懶加載的默認圖片
Vue.use(VueLazyLoad,{
    loading: def_lazy_img
}) //使用懶加載組件

//在使用img標籤的地方使用
<img v-lazy="item.al.picUrl" alt="">

六、歌詞滾動與高亮

由於api提供的歌詞包括時間,如:[03:57.280]原諒我這一輩子不羈放縱愛自由
因此首先要進行字符串切割:

<div class="lyric">
    <div class="roll-lyric" v-html="lyrics" ref="lyric"></div>
</div>

computed: {
    lyrics() {
        let lyrics = ''
        this.lyricArr = []
        if (this.lyric) {
            let arr = this.lyric.split('\n')
            for (let item of arr) {
                if (item) {
                    let arr2 = item.split(']')
                    this.lyricArr.push(arr2[0].substring(1,3)*60+arr2[0].substring(4)*1)
                    if (arr2) {
                        lyrics += `<p class='lyrichook' style='margin: 10px 0'>${arr2[1]}</p>`
                    }
                }
            }
        } else {
            lyrics = '暫無歌詞~'
        }
        return lyrics
    }
}

而後在播放的監聽事件中與播放的當前作對比:

this.$refs.myAudio.addEventListener('play', () => {
    this.pDOM = [...document.querySelectorAll('.lyrichook')]
    timer = setInterval(() => {
        this.now = audioDOM.currentTime
        this.lyricArr.forEach((item, index) => {
            if (parseInt(item) == parseInt(this.now)) {
                this.pDOM.forEach((p) => {
                    p.style.color = 'rgba(255,255,255,.8)' //其它歌詞清除高亮
                });
                this.pDOM[index].style.color = '#f12c61' //歌詞高亮
                this.$refs.lyric.style.transform = `translateY(-${(index-2)*25}px)` //歌詞滾動
            } 
        });
    }, 1000)
})

到這就ok了?

七、vuex狀態管理

推薦官方調試工具 devtools extension

想進一步理解vuex,能夠看這篇博客vuex學習實踐筆記

以前看到好多人寫的vuex,把整個項目的數據放到了一個state裏,致使應用的全部狀態集中到一個很大的對象。可是,當應用變得很大時,store 對象會變得臃腫不堪。

因此我建議(我的看法,輕噴):將 store 分割到模塊(module)。每一個模塊擁有本身的 state、mutation、action、getters。這樣方便管理與後期的維護。

車已到站✌️。

不知不覺寫了這麼多,老鐵們湊合這看吧?,以爲還行的能夠點個star,你的star是我繼續開源創做的動力,謝謝!!!

項目地址: https://github.com/hzzly/MagicMusic
歡迎你們的star啦~

文章來源:hzzly技術分享

相關文章
相關標籤/搜索