前言:在最近的一個外包項目中包聯盟(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
先來個預覽:前端
更多預覽:更多vue
?老鐵們,準備發車(技能點):java
vue文檔node
vue-router文檔webpack
vuex文檔 不想看文檔的能夠看看我這篇博客vuex學習實踐筆記ios
axios文檔 或者這篇博客 Vuex2 與 Axios 開發(我也是參考這篇,感謝做者?)git
es6(阮一峯的es6入門) 能夠參考個人es6之路(還在繼續,輕噴)es6
?坐好,出發
[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整理的這麼好(點個贊?)
|——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了?
推薦官方調試工具 devtools extension
想進一步理解vuex,能夠看這篇博客vuex學習實踐筆記
以前看到好多人寫的vuex,把整個項目的數據放到了一個state裏,致使應用的全部狀態集中到一個很大的對象。可是,當應用變得很大時,store 對象會變得臃腫不堪。
因此我建議(我的看法,輕噴):將 store 分割到模塊(module)。每一個模塊擁有本身的 state、mutation、action、getters。這樣方便管理與後期的維護。
車已到站✌️。
不知不覺寫了這麼多,老鐵們湊合這看吧?,以爲還行的能夠點個star,你的star是我繼續開源創做的動力,謝謝!!!
項目地址: https://github.com/hzzly/MagicMusic
歡迎你們的star啦~
文章來源:hzzly技術分享