天天看點

JavaScript實時監聽歌曲播放進度顯示對應歌詞

前言

在之前我就想試試線上的音樂播放器的制作,昨晚動手實作了播放音樂的歌詞實時對應顯示的元件,下面就來看看其中的解析原理。

正文

這裡我以李玉剛的《剛好遇見你》為例,首先我們需要擷取到音頻檔案以及歌詞的lrc内容,lrc歌詞檔案内容如下:

"[00:00.00] 作曲 : 高進\n[00:01.00] 作詞 : 高進\n[00:12.56]我們哭了\n[00:15.27]我們笑着\n[00:18.60]我們擡頭望天空\n[00:21.43]星星還亮着幾顆\n[00:24.63]我們唱着\n[00:27.56]時間的歌\n[00:30.62]才懂得互相擁抱\n[00:34.00]到底是為了什麼\n[00:36.94]因為我剛好遇見你\n[00:40.32]留下足迹才美麗\n[00:43.69]風吹花落淚如雨\n[00:46.48]因為不想分離\n[00:49.57]因為剛好遇見你\n[00:52.59]留下十年的期許\n[00:55.69]如果再相遇\n[00:59.15]我想我會記得你\n[01:14.28]我們哭了\n[01:16.88]我們笑着\n[01:20.29]我們擡頭望天空\n[01:22.96]星星還亮着幾顆\n[01:26.11]我們唱着\n[01:29.11]時間的歌\n[01:32.56]才懂得互相擁抱\n[01:35.36]到底是為了什麼\n[01:38.47]因為我剛好遇見你\n[01:41.84]留下足迹才美麗\n[01:44.83]風吹花落淚如雨\n[01:47.97]因為不想分離\n[01:51.02]因為剛好遇見你\n[01:54.09]留下十年的期許\n[01:57.23]如果再相遇\n[02:00.69]我想我會記得你\n[02:03.69]因為剛好遇見你\n[02:06.43]留下足迹才美麗\n[02:09.57]風吹花落淚如雨\n[02:12.64]因為不想分離\n[02:15.76]因為剛好遇見你\n[02:18.78]留下十年的期許\n[02:21.83]如果再相遇\n[02:24.98]我想我會記得你\n[02:31.07]因為我剛好遇見你\n[02:34.13]留下足迹才美麗\n[02:37.25]風吹花落淚如雨\n[02:40.37]因為不想分離\n[02:43.43]因為剛好遇見你\n[02:46.48]留下十年的期許\n[02:49.58]如果再相遇\n[02:52.67]我想我會記得你\n"
           

現在對其歌詞進行解析,歌詞的解析寫法參考了js解析lrc歌詞-制作滾動歌詞,如下:

var lyrics = this.lrc.split("\n");//this.lrc代表歌詞檔案内容的引用
      var lrcObj = {};
      for(var i=0;i<lyrics.length;i++){
          var lyric = decodeURIComponent(lyrics[i]);
          var timeReg = /\[\d*:\d*((\.|\:)\d*)*\]/g;
          var timeRegExpArr = lyric.match(timeReg);
          if(!timeRegExpArr)continue;
          var clause = lyric.replace(timeReg,'');
          for(var k = 0,h = timeRegExpArr.length;k < h;k++) {
              var t = timeRegExpArr[k];
              var min = Number(String(t.match(/\[\d*/i)).slice(1)),
                  sec = Number(String(t.match(/\:\d*/i)).slice(1));
              var time = min * 60 + sec;
              lrcObj[time] = clause;
          }
      }
      return lrcObj;
           

上述代碼會将你的歌詞檔案轉換為數組,并且每個數組下标即為歌詞的播放時間(機關:秒),接着在頁面中添加一個音頻元件,并引入音頻檔案:

<audio id="player" src="../assets/ghyjn.mp3" autoplay>
      您的浏覽器不支援 audio 标簽。
</audio>
           

使用JS監聽播放動态,并對每次的時間進行轉換以此來對應數組下标然後更改頁面上對應的歌詞内容:

this.p.addEventListener("timeupdate",function(){
      let obj = _this.lrcObj[Math.floor(this.currentTime)];
      if(obj!=undefined){
        _this.g = obj;
      }
    });
           

因為我是使用Vue+Webpack寫的,是以頁面中的完整代碼如下:

<template>
  <div class="hello" :style="'height:'+height+';width:100%'">
      <audio id="player" src="../assets/ghyjn.mp3" autoplay>
      您的浏覽器不支援 audio 标簽。
      </audio>
      <br>
      <div class="c">
          <div class="tc font30 mb15">{{g}}</div>
      </div>
  </div>
</template>
 
<script>
export default {
  data () {
    return {
      g:'',
      gd:{
        up:null,
        down:null
      },
      p:null,
      lrc:"[00:00.00] 作曲 : 高進\n[00:01.00] 作詞 : 高進\n[00:12.56]我們哭了\n[00:15.27]我們笑着\n[00:18.60]我們擡頭望天空\n[00:21.43]星星還亮着幾顆\n[00:24.63]我們唱着\n[00:27.56]時間的歌\n[00:30.62]才懂得互相擁抱\n[00:34.00]到底是為了什麼\n[00:36.94]因為我剛好遇見你\n[00:40.32]留下足迹才美麗\n[00:43.69]風吹花落淚如雨\n[00:46.48]因為不想分離\n[00:49.57]因為剛好遇見你\n[00:52.59]留下十年的期許\n[00:55.69]如果再相遇\n[00:59.15]我想我會記得你\n[01:14.28]我們哭了\n[01:16.88]我們笑着\n[01:20.29]我們擡頭望天空\n[01:22.96]星星還亮着幾顆\n[01:26.11]我們唱着\n[01:29.11]時間的歌\n[01:32.56]才懂得互相擁抱\n[01:35.36]到底是為了什麼\n[01:38.47]因為我剛好遇見你\n[01:41.84]留下足迹才美麗\n[01:44.83]風吹花落淚如雨\n[01:47.97]因為不想分離\n[01:51.02]因為剛好遇見你\n[01:54.09]留下十年的期許\n[01:57.23]如果再相遇\n[02:00.69]我想我會記得你\n[02:03.69]因為剛好遇見你\n[02:06.43]留下足迹才美麗\n[02:09.57]風吹花落淚如雨\n[02:12.64]因為不想分離\n[02:15.76]因為剛好遇見你\n[02:18.78]留下十年的期許\n[02:21.83]如果再相遇\n[02:24.98]我想我會記得你\n[02:31.07]因為我剛好遇見你\n[02:34.13]留下足迹才美麗\n[02:37.25]風吹花落淚如雨\n[02:40.37]因為不想分離\n[02:43.43]因為剛好遇見你\n[02:46.48]留下十年的期許\n[02:49.58]如果再相遇\n[02:52.67]我想我會記得你\n",
      lrcObj:null,
      height:'auto'
    }
  },
  mounted(){
    this.p = document.querySelector("#player")
    let _this = this;
    this.lrcObj = this.jx();
    console.log(this.lrcObj);
    this.p.addEventListener("timeupdate",function(){
      let obj = _this.lrcObj[Math.floor(this.currentTime)];
      if(obj!=undefined){
        _this.g = obj;
      }
    });
    this.height =window.innerHeight+'px'
    window.onresize  = ()=>{
      _this.height =window.innerHeight+'px'
    }
  },
  methods:{
    jx(){
      var lyrics = this.lrc.split("\n");
      var lrcObj = {};
      for(var i=0;i<lyrics.length;i++){
          var lyric = decodeURIComponent(lyrics[i]);
          var timeReg = /\[\d*:\d*((\.|\:)\d*)*\]/g;
          var timeRegExpArr = lyric.match(timeReg);
          if(!timeRegExpArr)continue;
          var clause = lyric.replace(timeReg,'');
          for(var k = 0,h = timeRegExpArr.length;k < h;k++) {
              var t = timeRegExpArr[k];
              var min = Number(String(t.match(/\[\d*/i)).slice(1)),
                  sec = Number(String(t.match(/\:\d*/i)).slice(1));
              var time = min * 60 + sec;
              lrcObj[time] = clause;
          }
      }
      return lrcObj;
    }
  }
 
}
</script>
<style>
.hello{
  background-image: url("../assets/by.jpg")
}
.c{
  color: #927712;
}
.tc{
  text-align: center;
  margin:0 auto;
}
.mb15{
  margin-bottom: 15px;
}
.font40{
  font-size: 4rem;
}
.font30{
  font-size: 3rem;
}
</style>
           

原文連結

繼續閱讀