1. 程式人生 > >Lily_music 網頁音樂播放器 -可搜尋(附歌詞聯動播放效果解說)

Lily_music 網頁音樂播放器 -可搜尋(附歌詞聯動播放效果解說)

部落格地址:https://ainyi.com/#/59

寫在前面

這是我今年(2018)年初的小專案,當時也是手賤,不想用別的播放器,想著做一個自己的網頁播放器,有個歌曲列表、可關鍵詞搜尋、歌詞滾動播放的效果,於是乎,就做了這一個 Lily_music

當時的感慨

有好幾天沒有發表部落格了,這也是因為一直開發音樂和完善我的部落格專案,好不容易抽出時間總結一下這幾天所做的東西,還這麼多課,實則匆忙
今天難得逃了一次課,就趁這時間,該寫寫就寫寫吧~~

進入正題:Lily_music

本次開發,參照本人之前所做的 樂詩部落格(文末會說到)的相關播放控制等功能,繼續優化的結果

前端模仿qq音樂介面,然後在此之上進行修改的介面,並使用了一點 es6 的語法

話說個人挺喜歡qq音樂介面的,簡潔,當然也少不了背景模糊外掛以及滾動條美化相關外掛

也用到了彈窗、點選複製歌曲連結和歌詞連結相關功能,但是目前歌曲分享功能暫未實現、後續....

==致謝==:歌曲搜尋參照某位大佬封裝的 qq 音樂的 api,UI 介面參照另一位大神的一些解決方案,在此表示感謝

相關外掛

那麼相關使用的開源外掛有:

  1. jQuery 官方類庫:https://jquery.com
  2. layer 彈窗外掛:http://layer.layui.com
  3. 複製貼上庫外掛:https://www.npmjs.com/package/clipboard-js
  4. mCustomScrollbar 滾動條美化外掛:http://manos.malihu.gr/jquery-custom-content-scroller
  5. background-blur 背景圖片模糊特效外掛:https://msurguy.github.io/background-blur

還有播放、控制、歌詞解析、搜尋、載入動畫sg類庫等功能全部手寫,爽的不行

溫馨提醒

本播放器並不需要什麼特別的執行環境,直接下載開啟就能用了 ^_^

響應式優化,可在各種大小的裝置執行開啟

音樂搜尋的結果均來自 qq音樂 (後續會繼續擴大到多個平臺)

本播放器還有一些 bug,需求就是不斷滿足的,虛心請教...

談談開發

果斷使用的是 H5 播放器,十分好用

一般在做這種播放器的開發,要多多使用面向物件的開發思想

定義一個播放器物件,相關引數、方法如下:

播放器物件:krAudio
引數:
  播放器:audioDom
  進度條鎖定:locked:true
  進度條按下的鎖:kdown
  靜音的鎖:flag_volume
  當前音量:curentVoice
  當前播放的列表序號:Currentplay
  當前播放列表歌曲總數:allItem
  播放模式,1 為列表迴圈:orderModes

方法:
  播放器初始化:init
  設定播放的音樂地址:seturl
  播放:play
  暫停:stop
  播放時間監聽及處理:time
  時間格式化:format
  下一首:next
  上一首:prev
  播放模式:ordermode
  拖動進度條:controlTime
  拖動音量條:controlVoice

上面部分的引數及方法基本涵蓋播放器該有的功能,定義好了整個播放器物件所需要的引數和方法,就可以進行具體開發了

歌詞聯動播放

具體談談這個功能的實現

歌詞解析,我之前做的==樂詩部落格==採用的是自己寫的一種歌詞解析滾動播放的方法

首先明白一般歌詞的形式是:
[00:13.80]期望飛上恬靜月球遙望每家的窗
[00:18.24]誰伴深愛細味露臺玫瑰香

這樣子的形式,利用 ajax 非同步請求到歌詞檔案內容,然後就可以進行字串裁剪,單單取出時間和歌詞,html5 播放器可以獲取到當前播放時間,就可以實現==當前播放時間==和==當前歌詞==一一對應,附上程式碼:

loadLrc :function(){//載入歌詞
  var vallrc = $(".hidetextlrc").text();
  //如果沒有上傳歌詞或者刪除了歌詞
  if(!vallrc || $(".is_deleteLrc").text() == 1){
    $(".lrc_content_notext").text("暫無歌詞");
    $(".lrc_content_notext").show();
    return;
  }
  var isHrefLrc = $(".is_href_lrc").text();
  //如果是上傳的歌詞,那就要拼接上伺服器地址
  if(isHrefLrc == 0) vallrc = basePath + "/" + vallrc;
  $.ajax({  //非同步請求獲取本地歌詞
    url:vallrc,
    type:"post",
    success:function(data){
      //第一次分離歌詞
      var lrcArr = data.split("[");
      //存放分離後的歌詞
      var html = "";
      var lrclast = null; //記錄上一行的歌詞
      var lrcmes = null; //記錄當前行的歌詞
      var bofo = -1; //記錄上一行歌詞的秒數
      var ms = -1; //當前這一行的秒數
      for(var i = 0;i < lrcArr.length;i++){
        //第二次分割歌詞,變成["03:01.08","這個世界變得更加美麗"],陣列以逗號分隔
        var arr = lrcArr[i].split("]");
        //取到陣列arr下標為1的歌詞部分
        //將上一行的歌詞賦值給lrclast
        lrclast = lrcmes; 
        //得到當前歌詞
        lrcmes = arr[1];
       //取到時間
        var time = arr[0].split("."); //變成["03:01","08"]
        //取到time下標為0的分鐘和秒
        var ctime = time[0].split(":"); //變成["03","01"];
        //將上一行的秒數賦值給bofo
        bofo = ms;
        //轉化成秒數
        ms = ctime[0]*60 + ctime[1]*1;
        //如果上一行和當前行秒數相同,則當前行秒數++ ,解決秒數相同的辦法
        if(bofo == ms){
          ms++;
        } else if (ms >= 0){
          if(!isNaN(bofo)){ // 如果是數字
            var classeName = "l_"+bofo;
            var concon = bofo; // bofo會自增,所以下面for迴圈條件用這個變數來代替
            for(var j = 0;j < ms-concon-1;j++){
              classeName += " l_"+ ++bofo;
            }
            if(ms>=0 && lrclast != null){
              html += "<li class='"+classeName+"'>"+lrclast+"</li>";
            }
          }
        }
      }
      //裝載最後一行歌詞的機制,先獲取歌曲總時間
      setTimeout(function(){
        var allall = krAudio.audioDom.duration;
        var classlaName = "l_"+ms;
        var conben = ms; //ms會自增,所以下面for迴圈條件必須用這個變數來代替
        for(var j = 0;j < allall-conben-1;j++){
          classlaName += " l_"+ ++ms;
        }
        html += "<li class='"+classlaName+"'>"+lrcmes+"</li>";
        //把解析好的歌詞放入歌詞展示區中
        $("#lrcly").html(html);
        $("#lyrics").html(html);
      },200);
    }
  });
  // 聯動音樂播放歌詞
  krAudio.audioDom.addEventListener("timeupdate",function(){
    //獲取當前播放時間,獲得的是秒數
    var time = this.currentTime;
    //解析音樂對應的時間
    var m = parseInt(time / 60);//獲取此時的分鐘
    var s = parseInt(time); //轉換int型別,獲取此時的秒數
    $(".l_"+s).addClass("lrcsel").siblings().removeClass("lrcsel");
    //歌詞滾動條,使歌詞在中間的計算公式:
    //第n行歌詞*li的高度-歌詞區域中間的li(就是包括這個li,取這個li的一半)以上的li的總高度
    //區域性歌詞的控制
    $(".lrc_content_box").stop().animate({
      scrollTop:(($(".lrcsel").index()+1)*29 - 145)//減去偏差,使當前歌詞在中間
    },240);
    //全屏歌詞的控制
    $("#lyrics").stop().animate({
      scrollTop:(($(".lrcsel").index()+1)*24 - 168)//減去偏差,使當前歌詞在中間
    },240);
  });
},

這種==歌詞解析==、==聯動播放==的實現是我之前==樂詩部落格==採用的一種方案,感覺也不錯

重點來了

此次採用的是另一種歌詞解析方式,利用 js 正則表示式全部替換的方式

替換方式

var reg = /-/g;  // g表示全部替換 ,要替換的字串是-
createTime = createTime.replace(reg,"/"); // 第二個引數表示替換成 /
 // 替換成2018/04/03

歌詞解析

//解析歌詞
function parseLyric(lrc) {
 var lyrics = lrc.split("\n");
 var lrcText = {};
 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;
     lrcText[time] = clause;
   }
 }
 return lrcText;
}

這樣子解析出來的是一個物件,存放著鍵值對
鍵:==時間(秒)==
值:==歌詞==

就可以直接做一個 for in 迴圈將每句歌詞新增到歌詞區域,將時間新增到每句歌詞的樣式控制 class 名

根據每句歌詞的時間,就可以在播放器的 timeupdate 監聽事件裡實現滾動播放歌詞了(程式碼上面有)

拖動進度條

滑鼠拖動進度條的時候,有三個監聽事件

按下:onmousedown
移動:onmousemove
彈起:onmouseup

這裡滑鼠移動事件需要放在滑鼠按下事件裡面,當滑鼠彈起時,在裡面清除移動、彈起兩個事件,以免彈起時還執行滑鼠按下拖動事件(也可以定義一把鎖來控制)

還有很多細節點的問題,上一曲下一曲臨界值、搜尋後的播放控制、列表小選單與主按鈕之間的聯動、三種播放模式(順序播放、隨機播放、單曲迴圈)等等等等... 有坑也有歡笑

截圖展示

1.jpg
2.jpg
3.jpg

專案連結

線上演示:Lily_music
GitHub:https://github.com/Krryxa/Lily_music
歡迎 start

部落格地址:https://ainyi.com/#/59