爲了提升本身,最近在學習微信小程序,選題是仿網易雲音樂。期間踩過了大把的坑,bug出現的難受和解決bug歡喜,一直是伴隨我階段性學習這個項目的心情。初步完成了項目的主要功能,來分享一下本身的心路歷程。css
(圖一)html
(圖二)git
(圖三)github
(圖四)小程序
(圖五)微信小程序
*api
小程序的開發模式是MVVM模式。簡單的講就是頁面綁定的值改變,頁面就發生改變;頁面改變,頁面的綁定的值改變。這樣的話,列表式渲染就十分好用。只用寫一個通用的骨架,而後使用列表渲染生成頁面,這樣很是省時間省力氣。因此這個項目,大量充斥着列表渲染。 有的頁面部分可能會出如今好幾個頁面上。在這個項目裏,頁面頂部的部分出如今多個部分中,同時小程序裏不少地方須要用到**彈性佈局居中效果**因而我便把經常使用css樣式寫在app.wxss中,這樣能夠複用。 頁面右上角的四根豎線出如今多個頁面中,那變能夠單獨拿出來寫,而後在經過template,導入至不一樣的頁面中去。 選歌很須要解決的一點就是怎麼才知道選擇的是哪一首歌,歌單是哪個歌單。一個頁面獲取到其餘頁面想傳遞過來的數據的方式有不少。其1、能夠經過url跳轉的時候,傳參跳轉,再經過跳轉頁面中onload事件添加options參數得到。其2、能夠經過點擊事件改變全局屬性globalData的某項的值,而後再跳轉頁面中獲得globalData中相應的值,便能知道頁面跳轉中想傳遞的值。這個項目使用了這兩種方式,url傳參獲取播放第幾首歌曲,全局屬性globalData傳遞歌單。
bindload
。
這裏有一個小小的技巧,第一張圖的swiper-item不參與頁面渲染,這樣第一張圖就必定會進行加載。在第一張圖加載完成後,再進行頁面渲染。同時讓swiper開始輪播效果和生成指示點。微信
在播放界面時,一開始使用的<audio>
組件,洋洋灑灑敲下了一連串的代碼,播放音樂,一切正常。但當咱們前往另外一個頁面時,播放的音樂就沒聲音了。查了文檔才知道audio
並不能實現後臺播放,實現後臺播放的是wx.getBackgroundAudioPlayerState()
和wx.getBackgroundAudioManager()
兩個api。前者在微信客戶端1.2.0版本就不開始維護了,後者低版本需作兼容處理。這個項目我使用的是第二個api。
(備註:wx.getBackgroundAudioManager()官方文檔)
值得注意的是,當音頻對象的src取得連接時,就自動開始播放。網絡
歌曲播放時頁面動起來,歌曲未播放時靜止app
看見動畫了,第一個反應是css的animation,後來通過思考,若是不進行dom操做就要控制動畫的進行與否須要作的數據綁定就會不少,不方便使用。因而查文檔發現`wx.createAnimation(OBJECT)`這個api,但使用這個api,若是須要作到動畫的循環播放,要寫的js也不少很麻煩。通過了各類踩坑,根據小程序中的`progress`進度條組件,發現一個很棒的方法,那就是行內樣式綁定數據。
(備註:指針動畫簡單,進行一次就結束,這裏不提。。)
(備註:進度條是小程序自帶的組件,已播放時間完成方式和進度條類似,這裏與動畫效果一併提出)
這樣,只用在播放時,設計計時器,定時的按比列更改rotata、left、progress、的值,頁面就會有相關改變。這個函數中,一開始即是清除計時器,由於有一個坑點:點擊下一曲或上一曲時,計時器並未清除,那麼,便會有兩個計時器同時做用於一個值得改變(這種頭疼的狀況相信不少人都遇到過)。把三個計時器(轉盤、按鈕、進度條)在函數運行的開始就作清除,這樣就讓每次調用函數時,都先清除上一層的計時器,作到只有一個計時器做用於一個值。這種方式,用少許的代碼,造成了可控的動畫效果,非常方便。
(我在這收穫了另外一種寫動畫效果的方式,哈哈)
next: function () { // 全局定義了proSet rotSet timeSet,由於須要清除計時器 var timeCount; clearInterval(proSet); clearInterval(rotSet); clearInterval(timeSet); proSet = setInterval(() => { if (this.data.progress >= 100) { i++; if(i==this.data.music.length){ i=0; } app.globalData.i=i; backgroundAudioManager.stop(); this.nameBackMusic(); timeCount = 0; this.setData({ progress: 0, left: 0, songTime: this.data.music[i].songTime, songer: this.data.music[i].songer, songName: this.data.music[i].songName, time: secondToDate(this.data.music[i].songTime) }); } else if (this.data.run == 0) { clearInterval(proSet); clearInterval(rotSet); clearInterval(timeSet); } this.setData({ progress: 0.01 + this.data.progress, left: 0.0458 + this.data.left }); }, this.data.music[i].songTime / 10); rotSet = setInterval(() => { this.setData({ rotate: 1 + this.data.rotate, }); }, 24); timeCount = backgroundAudioManager.currentTime; if (typeof (backgroundAudioManager.currentTime) === "undefined") { timeCount = 0; } timeSet = setInterval(()=>{ timeCount++; this.setData({ currentTime: secondToDate(timeCount), //secondToDate用來把n秒轉換爲xx:xx的顯示形式 }); },1000) }
在播放界面中,設計一個值run
初始值爲0,用來記錄是否播放,播放時run爲1,暫停時run爲0。在頁面跳轉在返回播放頁面時,以前由於播放設置的data值會所有還原,致使頁面靜態顯示(進度條不動、時間不增長等)。這個時候,全局屬性globalData就上場了。不管是在選歌、播放、暫停的時候,globalData中的變量記錄播放的狀態(是否播放、播放哪一首歌等)。而播放頁面從新打開會執行onShow()
生命週期函數,這個時候變能夠從全局變量中獲得播放的狀態,而後決定播放頁面是否要動起來和相應的數據)。
由於頁面第一次加載也會執行onShow()
函數,而暫停音樂時backgroundAudioManager.paused
返回true,播放時放回fals,沒有音樂播放時返回undefined,若是單純的用:if(backgroundAudioManager.paused)
則會判斷無音樂和音樂播放時都爲假,這樣兩種不一樣的狀況執行相同的操做,則會發生意外,因此須要添加這樣的判斷if (typeof (backgroundAudioManager.paused) !== "undefined")
用以區分播放和無音樂事件。
一路學習過來,期間碰到的大大小小的問題數不勝數,收穫很大。目前還有一些功能暫未實現,會在之後繼續完善項目,繼續學習。
這個項目給我最大的啓示就是文檔是一個好東西,鍛鍊看文檔的能力會本身接受新東西的速度變快。再就是不少時候解決問題的方法多種多樣,寫代碼時能夠多作幾回考慮用哪一種方式實現一個功能,這樣既讓項目變得更高校,也讓本身變得更優秀。
我的郵箱:QiuShuiZC@163.com
github地址:秋水白
wx: zcfusheng
你們能夠一塊兒交流學習,若是以爲這個項目不錯的話,用star來砸我吧。
(備註:我給項目裏放的音樂都是周董和姿媽的,哈哈,畢竟男杰倫,女燕姿)