使用jQuery仿製網易雲音樂移動端

Lin-Ya發表於2019-03-02

預覽地址

2018年05月01日21:37:28 完成了主頁的推薦音樂、熱歌榜、搜尋和播放頁面。


2018年4月20日15:18:13 這是一個專案筆記,用於記錄製作這個專案的點點滴滴。


明確需求

原型圖
左一開始:主頁(推薦音樂)、熱歌榜、搜尋、歌單和播放介面。

製作歷程

自定義一個工作流

我選擇了browser-sync,因為這個專案比較輕量(不需要引入很多的模組),所以就直接用一個browoser-sync配合開發實時重新整理就行了。專案完成以後再用打包工具build一個dist就好了~~

旋轉的光碟

到底是怎麼實現光碟旋轉?CSS動畫,利用keyframes:

@keyframes circle {
	0% {
		transform: rotate(0deg);
	}
	100% {
		transform: rotate(360deg);
	}
}
.disc {
	animation:circle 20s infinite linear;
	/*選擇動畫,circle;時間;無限迴圈;線性變化*/
}
複製程式碼
  1. 父容器page,上半層為點唱機disc-container容器,下半層為歌曲資訊song-description。(把各個img素材新增進去。)
  2. 底部為兩個按鈕連線,用一個div包裹links容器。(mock資料)
  3. page一個滿屏的高度,100vh。三個部分由上到下列式排布,用flax吧。然後根據判斷就給各個img設定寬高。

歌詞

  1. 先拿到歌詞請求。利用開發者工具裡面的network > filter > XHR拿到請求。複製一份,用來mock一份歌詞。儲存為json檔案。
  2. 引入jQuery,傳送一個ajax請求剛剛儲存的lyric.json並把響應打出來(promise)
  3. 對lyr進行處理。(lyr指的是響應裡面的key為lyric的值。lyr = object.lyric) 這是一個字串,我們通過以回車為分隔符(‘\n’)組成一個新的陣列打出來。 效果如下:
    效果圖
  4. 用到正則,匹配中括號裡面的時間和後面的歌詞內容。然後利用正則的api捕獲內容返回給array。注意,這裡用到map,是對array裡面的每一項string進行match。
  5. 把array的內容生成html的P標籤插入document中,屬性是時間。
  6. 高度為顯示三行歌詞的高度。設定好字型大小,居中。
  7. 設定好active樣式,給歌詞lyric設定一個固定高度,給歌詞片段p設定行高。
  8. 歌詞播放的時候調整lines(就是存放歌詞的div)的transform的樣式。

播放

  1. 拿到歌曲的src
  2. 把audio的各種api熟悉一下(播放、暫停、獲取當前時間、audio的事件)
  3. 當歌曲播放的時候,上方轉盤跟著旋轉。
  4. 新增播放按鈕(這裡我使用了圖片)。

暫停

  1. 點選唱片,audio.pause(),同時移除表示playing的狀態class。

首頁

首頁的製作相對簡單些。

  1. logo從官方的網頁剪下來,是一個svg(透明的,加個背景色就能看見了。)
  2. 完成其CSS樣式(這個就比較費時間和功夫了)
  3. 獲取幾首歌作為樣本。可以選擇放在七牛用來mock ajax請求。
  4. mock一個song.json,然後把html上寫死了的節點刪除。根據返回的json拼接成html並插入到dom上。
  5. 首頁載入以後,在相應資料到來之前,應該顯示一個loading的動畫表示正在載入資料;當資料到來以後渲染頁面元素,並移除loading動畫,目的就是為了提升使用者體驗。(可以用gif,也可以旋轉一個svg圖示。)
  6. 傳送ajax請求,根據響應對跳轉連結的地址進行拼接,同時對歌曲資訊進行拼接。(ES6模板字串)
    程式碼截圖
  7. 拼接完畢以後就渲染到html上,並把載入動畫移除。
    效果圖
  8. 點選以後,就會跳轉到./song.html,同時附帶上歌曲的id。在song.js上,根據location.search獲得歌曲的id。(需要用正則匹配)
location.search.match(/\bid=([^&]*)/)[1]
複製程式碼

熱歌榜

其實熱歌榜的難度不大,裡面的歌曲載入可以服用前面首頁的loadmusic,所以就略過吧。

搜尋

  1. 需要對api進行修改,把搜尋建議的目標地址改一下,改為suggest/keyword 如果響應裡面的code===200,說明成功了。
    效果
  2. 搜尋提示可點選、熱搜tag可點選。

歌詞滾動

  1. 首先要獲取當前歌曲的進度時間:audio.currentTime得到的是當前播放進度的秒數(注意,需要設定定時每隔500毫秒獲取一次)
  2. 轉換為正常的時間顯示01:25,實質是把分鐘數和秒數拼接一起,需要解決的就是數字的取整,判斷是否需要加0
setInterval(()=>{
	let  nowScends  =  audio.currentTime;
	let  minutes  =  ~~(nowScends/60)
	let  scends  =  ~~(nowScends%60)
	let  currentTime  = `${padTime(minutes)}:${padTime(scends)}`;
 },300)
function  padTime(number)  {
      return  number>10?number+'':'0'+number
    }
複製程式碼
  1. 實現歌詞滾動的程式碼:
let  $lrcArray  =  $('.lyric .lines>p'); //這裡取的是每一段歌詞的集合。
let  lrcLength  =  $lrcArray.length;
for(let  i=0;  i<lrcLength;  i++){
	let  $whitchLines  =  $lrcArray.eq(i);	//指應當顯示的歌詞行
	let  $nextLines  =  $lrcArray.eq(i+1);	//指接下來要顯示的歌詞行
	
	//當沒有下一段歌詞的時候,意味歌曲播放到最後,return。
	if($nextLines.length  ===  0){            
		return;
	}else if($whitchLines.attr('data-time')  <  currentTime  &&  $nextLines.attr('data-time')>currentTime){
		//遍歷所有歌詞,針對其屬性`data-time`與當前的`currentTime`進行比較,如果當前時間比`i`的`data-time`大,比`i+1`的小,說明此時歌詞應該是在`i`與`i+1`之間,應該顯示$whitchLines的內容。
		$whitchLines.addClass('active').siblings().removeClass('active')
		let  gap  =  $whitchLines.offset().top  -  $('.lines').offset().top  ;
		log('gap ='+  gap)
		//因為歌詞顯示區域的高度是顯示五行歌詞,那麼中間的高度就是總高度的五分之三
		let  middle  =  $('.lyric').height()  /  5  *  2
		$('.lines').css('transform',`translateY(-${gap-middle}px)`)
	}
}
複製程式碼

難點記錄與解決歷程

1. `處理歌詞data,需要會用正則來對字串進行分割。`
解決:可以利用線上正則網站好好設計一遍你的正規表示式。

2. `對播放動畫進行設計,實現播放暫停的時候唱片旋轉角度不會歸零。`
解決:使用 `animation-play-state: paused `
3. `mock資料會很繁瑣。`
解決:七牛儲存/自建api

4. `搜尋框提示`和`搜尋顯示內容的節流`

5. `歌詞滾動`
解決:要想好好歌詞顯示的邏輯:
	- 確定歌曲時間戳(`audio.currentTime`)
	- 根據時間戳匹配歌詞(遍歷歌詞節點,根據歌詞節點的`data-time`屬性與時間戳進行比較,當時間戳位於兩行歌詞的`data-time`之間,高亮上一條歌詞)
	- 滾動歌詞(`transform:translateY`)
複製程式碼

待更新

相關文章