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;時間;無限迴圈;線性變化*/
}
複製程式碼
- 父容器
page
,上半層為點唱機disc-container
容器,下半層為歌曲資訊song-description
。(把各個img素材新增進去。) - 底部為兩個按鈕連線,用一個div包裹
links
容器。(mock資料) - 給
page
一個滿屏的高度,100vh。三個部分由上到下列式排布,用flax吧。然後根據判斷就給各個img設定寬高。
歌詞
- 先拿到歌詞請求。利用開發者工具裡面的network > filter > XHR拿到請求。複製一份,用來mock一份歌詞。儲存為json檔案。
- 引入jQuery,傳送一個ajax請求剛剛儲存的lyric.json並把響應打出來(promise)
- 對lyr進行處理。(lyr指的是響應裡面的key為lyric的值。lyr = object.lyric)
這是一個字串,我們通過以回車為分隔符(‘
’)組成一個新的陣列打出來。
效果如下: - 用到正則,匹配中括號裡面的時間和後面的歌詞內容。然後利用正則的api捕獲內容返回給array。注意,這裡用到map,是對array裡面的每一項string進行match。
- 把array的內容生成html的P標籤插入document中,屬性是時間。
- 高度為顯示三行歌詞的高度。設定好字型大小,居中。
- 設定好active樣式,給歌詞lyric設定一個固定高度,給歌詞片段p設定行高。
- 歌詞播放的時候調整lines(就是存放歌詞的div)的transform的樣式。
播放
- 拿到歌曲的src
- 把audio的各種api熟悉一下(播放、暫停、獲取當前時間、audio的事件)
- 當歌曲播放的時候,上方轉盤跟著旋轉。
- 新增播放按鈕(這裡我使用了圖片)。
暫停
- 點選唱片,
audio.pause()
,同時移除表示playing的狀態class。
首頁
首頁的製作相對簡單些。
- logo從官方的網頁剪下來,是一個svg(透明的,加個背景色就能看見了。)
- 完成其CSS樣式(這個就比較費時間和功夫了)
- 獲取幾首歌作為樣本。可以選擇放在七牛用來mock ajax請求。
- mock一個song.json,然後把html上寫死了的節點刪除。根據返回的json拼接成html並插入到dom上。
- 首頁載入以後,在相應資料到來之前,應該顯示一個loading的動畫表示正在載入資料;當資料到來以後渲染頁面元素,並移除loading動畫,目的就是為了提升使用者體驗。(可以用gif,也可以旋轉一個svg圖示。)
- 傳送ajax請求,根據響應對跳轉連結的地址進行拼接,同時對歌曲資訊進行拼接。(ES6模板字串)
- 拼接完畢以後就渲染到html上,並把載入動畫移除。
- 點選以後,就會跳轉到
./song.html
,同時附帶上歌曲的id。在song.js
上,根據location.search
獲得歌曲的id。(需要用正則匹配)
location.search.match(/id=([^&]*)/)[1]
複製程式碼
熱歌榜
其實熱歌榜的難度不大,裡面的歌曲載入可以服用前面首頁的loadmusic,所以就略過吧。
搜尋
- 需要對api進行修改,把搜尋建議的目標地址改一下,改為suggest/keyword 如果響應裡面的
code===200
,說明成功了。
- 搜尋提示可點選、熱搜tag可點選。
歌詞滾動
- 首先要獲取當前歌曲的進度時間:
audio.currentTime
得到的是當前播放進度的秒數(注意,需要設定定時每隔500毫秒獲取一次) - 轉換為正常的時間顯示
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
}
複製程式碼
- 實現歌詞滾動的程式碼:
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`)
複製程式碼
待更新