vue專案:歌詞隨歌曲同步滾動
阿新 • • 發佈:2018-12-22
封裝成物件,暴露出去共享使用
1、新建js檔案
2、因為需要用到元素運動來實現歌詞自上而下滾動的效果,又不想引用jquery增大js的載入,所有在物件內部封裝了一個運動函式。
3、主要的函式是新增定時器來實現歌詞和歌曲的播放的時間同步,因為歌曲有暫停的功能,所以也添加了清除定時器來實現歌詞暫停的功能,此時在物件內部的兩個函式中用到了同一個引數定時器,所有需要將定時器定義成物件自身的一個引數來實現引數共享。
4、因為要滿足點選某一首歌曲來播放相關的歌詞,所以也需要一個函式來重置物件自身的引數。物件內部也需要解析歌詞資料的函式,將解析後的歌詞資料中的時間點都統一轉化成秒,來和audio的當前播放進度(Audio.currentTime)對比,達到歌詞滾動同步歌曲播放進度的效果。
5、每次點選播放某一首歌曲都要先重置物件自身的引數,再進行歌詞同步滾動。
新建的js程式碼如下:
export default { second2: 0, // 當前歌曲播放到多少毫秒 gdtimer: '', // 歌詞滾動的定時器 height: 20, // 每一行歌詞的高度 obj: {}, // 解析歌詞後的物件 obj2: {}, // 備份obj // 字串轉換成秒 parse2 (stri) { var arr = stri.split(':') var num = 0 num = parseInt(arr[0]) * 60 + parseFloat(arr[1]) return num }, // 解析歌詞 parse (str) { var arr1 = [] var arr2 = [] this.obj = { time: [], content: [] } this.obj2 = { time: [], content: [] } arr1 = str.split('[') arr1.forEach((value, index) => { if (index > 0) { arr2 = arr2.concat(value.split(']')) } }) arr2.forEach((value, index) => { if (index % 2 === 0) { this.obj.time.push(this.parse2(value)) this.obj2.time.push(this.parse2(value)) } else { this.obj.content.push(value) this.obj2.content.push(value) } }) }, // 將歌詞新增到 P 標籤中 addcontent (conp) { this.obj.content.forEach((value, index) => { conp.innerHTML = conp.innerHTML + value + '<br>' }) }, // 實現歌詞滾動 gundong (conp) { this.gdtimer = setInterval(() => { var myaudio = document.querySelector('#main-audio') // console.log(myaudio.currentTime) this.second2 = myaudio.currentTime // this.second2 = this.second2 + 10 if (this.second2 >= this.obj2.time[0]) { // 刪除time陣列中已經過的時間 this.obj2.time.shift() console.log(this.second2, this) // 獲取 p標籤的top值 var top = window.getComputedStyle(conp).top this.startMove(conp, { top: parseInt(top) - this.height }) } if (this.obj2.time.length <= 0) { this.second2 = 0 this.lyticsEnd(conp) // clearInterval(this.gdtimer) } }, 50) }, // 暫停歌詞 pause () { if (this.gdtimer !== '') { clearInterval(this.gdtimer) // console.log(this.obj) } }, // 歌曲放完,重置該物件 lyticsEnd (conp) { this.pause() conp.innerHTML = '' conp.style.top = this.height + 'px' // 大坑。單位必須帶 this.obj = {} this.obj2 = {} this.second2 = 0 console.log('重置該物件成功', this) }, // 運動函式 startMove (obj, json, fnEnd) { var that = this clearInterval(obj.timer)// 先清除之前的定時器 obj.timer = setInterval(function () { var bStop = true// 假設所有的值都到了 for (var attr in json) { // 遍歷json屬性 var cur = (attr === 'opacity') ? Math.round(parseFloat(that.getStyle(obj, attr)) * 100) : parseInt(that.getStyle(obj, attr))// 對opacity 特殊處理 var speed = (json[attr] - cur) / 6 speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed) // speed 數字轉化,防止不能到達目標的bug if (cur !== json[attr]) bStop = false// 如果沒有達到目標值,則bStop設為false; if (attr === 'opacity') { obj.style.filter = 'alpha(opacity=' + (cur + speed) + ')' obj.style.opacity = (cur + speed) / 100 } else { obj.style[attr] = cur + speed + 'px' } } if (bStop) { clearInterval(obj.timer) if (fnEnd) fnEnd() // 執行回撥函式 } }, 30) }, getStyle (obj, name) { return obj.currentStyle ? obj.currentStyle[name] : window.getComputedStyle(obj, null)[name] // 瀏覽器相容性處理,注意getComputedStyle為只讀屬性 }, getByClass (oParent, sClass) { var aEle = oParent.getElementsByTagName('*') var aResult = [] var re = new RegExp('\\b' + sClass + '\\b', 'i') for (var i = 0; i < aEle.length; i++) { if (re.test(aEle[i].className)) aResult.push(aEle[i]) } return aResult } }
vue檔案中如下使用:
import lyrics from '../footer/lyrics' // js檔案路徑視情況而定 var conp = document.querySelector('.con-p') // 包裹歌詞的元素容器 lyrics.lyticsEnd(conp) // 重置物件 lyrics.parse(this.lyrics, conp) // 解析歌詞 this.lyrics 代表歌詞資料 lyrics.addcontent(conp) // 向元素容器中新增歌詞內容 lyrics.gundong(conp) // 歌詞滾動函式