云開發(fā)練手項目:音樂播放器(上)

本文目錄:

  • 1.云開發(fā)的優(yōu)勢
  • 2.云開發(fā)的五大基礎能力
  • 3.基本結構分析:
  • 4.寫輪播圖
  • 5.組件化開發(fā)流程
  • 6.數(shù)據(jù)監(jiān)聽器observers
  • 7.異步操作解決方案
  • 8.小程序中怎樣使用async函數(shù)
  • 9.第一個云函數(shù)getPlaylist
  • 10.小程序端調用云函數(shù)
  • 11.云函數(shù)獲取數(shù)據(jù)庫中的大于100條的數(shù)據(jù)
  • 12.小程序端調用云函數(shù)
  • 13.tcb-router
  • 14.本地數(shù)據(jù)存儲
  • 15.音樂播放的控制
  • 16.如何實現(xiàn)組件間傳值
  • 17.給小程序設置全局屬性和方法

1.云開發(fā)的優(yōu)勢

正常的開發(fā)分為前端和后端
傳統(tǒng)的小程序開發(fā)完成之后需要進行一個上線部署,而傳統(tǒng)部署的基本步驟有:購買服務器、域名,備案,網(wǎng)絡防護,負載均衡,監(jiān)控警告等。這些事情非常的繁瑣,讓人頭疼。


傳統(tǒng)模式.png

小程序云開發(fā),弱化了后端和運維的工作,不需要搭建服務器。
云開發(fā)賦予了開發(fā)者穩(wěn)定,安全的讀取數(shù)據(jù),上傳文件的能力。


云開發(fā)模式.png

serverless=》無服務開發(fā)=》小程序的云開發(fā)

在云開發(fā)的核心理念中,函數(shù)即服務,依托騰訊端提供的后端服務,我們通過函數(shù)就可以實現(xiàn)調用,從而實現(xiàn)serverless

2.云開發(fā)的五大基礎能力

  • 1.云函數(shù):在云端運行代碼,并且具有天然的鑒權機制。
  • 2.云數(shù)據(jù)庫:既可以在云函數(shù)端操作,又可以在小程序端操作的非關系型json數(shù)據(jù)庫(類似moongodb)
  • 3.云調用:基于云函數(shù)免鑒權使用小程序開放接口的能力
  • 4.HTTP API:可以讓第三方服務很方便的在已有服務器上訪問云資源,實現(xiàn)與云開發(fā)的互通。
  • 5.云存儲:在云端存儲文件,可以在云端控制臺可視化管理

我們可以通過云函數(shù)去定期的去第三方數(shù)據(jù)服務器拿數(shù)據(jù),然后更新到云數(shù)據(jù)庫中

1.什么是小程序的云開發(fā)?

傳統(tǒng)模式:小程序端展現(xiàn)的數(shù)據(jù)是發(fā)請求給后端拿到的

云開發(fā)模式:小程序端提供的原生接口可以直接去操作遠程的云數(shù)據(jù)庫,云函數(shù),云存儲。而我們根本根本不知道后端部署在那里。

2.什么是serverless?

打破前端和后端的物理隔離

當我們使用后端服務的時候,不需要關注后端的ip地址是什么等等

在小程序官網(wǎng)上注冊賬號,然后下載開發(fā)者工具,打開開發(fā)者工具,創(chuàng)建一個新項目。
需要注意一點,APPID是每一個小程序的唯一標識,這個ID在官網(wǎng)賬號中的“開發(fā)”界面可以查看到。
進入項目之后,第一次使用云開發(fā)的用戶需要點擊界面上方的“云開發(fā)”按鈕去開通服務。
首先可以選擇創(chuàng)建一個test作為開發(fā)環(huán)境的云服務,等到項目上線再創(chuàng)建一個生產(chǎn)環(huán)境進行使用。

3.基本結構分析:

cloudfunctions=》云函數(shù)部分

miniprogram=》前端部分代碼

  • images圖片資源
  • pages創(chuàng)建小程序的時候自帶文件夾和文件(可以全部刪除)
  • style創(chuàng)建小程序的時候自帶樣式(可以全部刪除)
項目文件結構.png

app.js全局js文件
onLaunch:function(){}
當小程序啟動的時候觸發(fā)的鉤子函數(shù)
wx.cloud.init({ env:"在此處填入環(huán)境ID",
這個地方填入的是哪個ID,小程序自動連接的就是對應的環(huán)境,先填開發(fā)環(huán)境,上線的時候把這個地方改成生產(chǎn)環(huán)境就可以了。
traceUser: true
設置為true的時候,每一個訪問過我們的小程序的用戶都會被記錄,并且以倒序的順序進行顯示
})

app.json全局配置文件

pages
//文件的路徑
window
//窗口的一些配置(頁面的最上方)
“sitemapLocation”:sitemap.json
//小程序開放的內部搜索,對應的配置文件sitemap.json,決定了我們的小程序界面是否能被搜索到,在小程序優(yōu)化中可以用到
tabBar
//小程序封裝的一個對象,有color,selectedColor,list等常用屬性。
//對應的小程序頁面下方的導航,最少兩個,最多五個

app.wxss全局樣式
README.md小程序的開發(fā)說明
project.config小程序項目的配置文件,突出為整個項目
iconfont下載圖標很方便,可以自由選擇格式,大小,以及顏色(點擊下載,直接下載到本地就可以直接使用了)

把style文件夾中的guide.wxss和app.wxss中的小程序自帶樣式都去除掉,樣式都是我們自定義
寫最初的幾個主頁面:
先在app.json中的“pages”中把框架自帶的頁面全部刪除,然后加上自己要寫的幾個頁面路徑,保存之后在對應的路徑就會自動生成頁面文件。(手動把框架自帶的頁面文件刪除掉)

4.寫輪播圖

小程序原生自帶swiper組件,里面的項目swiper-item,在swiper-item里放image標簽
小程序自帶的block標簽,建議把wx:for寫在block上面,block不會真實渲染,在輪播圖這里我們在swiper-item外面包裹一層block,然后wx:for渲染寫在block標簽上

swiper的常用屬性:

  • indicator-dots="true",顯示導航的小點,默認為flase
  • autoplay=“true”自動播放
  • interval=“2000”自動播放的間隔是2000ms
  • duration=”1000“滑動播放時長為1000ms

小程序自帶的image標簽的常用屬性

  • mode=”scaleToFill“,保證圖片完全覆蓋當前image容器,這種縮放模式下圖片非常有可能會產(chǎn)生變形,實際效果不好
  • mode=”aspectFit“,讓圖片能夠完整的顯示在容器中,缺點是有可能會讓容器留白
  • mode=”widthFix“,讓圖片能夠完全覆蓋容器,同時保持圖片的寬高比不變,同時給image標簽增加width100%height100%的樣式,保證image能夠完整覆蓋父元素。這個縮放模式是實際項目中最常用的。

5.組件化開發(fā)流程

組件:在用戶界面開發(fā)領域,組件是一種面向用戶的,獨立的,可復用的交互元素的封裝。

組件的組成:
結構=》wxml
邏輯=》js
樣式=》wxss

組件的設計原理:高內聚,低耦合,單一職責,避免過多參數(shù)
封裝第一個組件:歌曲列表組件
1.創(chuàng)建
首先在項目的miniprogram文件夾下新建一個文件夾components,然后在components中右鍵創(chuàng)建對應的組件(這里是playlist)
2.在頁面中引用和使用
在頁面的json中進行引用

{
  "usingComponents": {
    "x-playlist": "/components/playlist/playlist"
  },
  "enablePullDownRefresh":true
}

在頁面的wxml中進行使用

3.傳遞數(shù)據(jù),這里想把頁面中的歌曲數(shù)據(jù)playlist傳遞給組件

<view class="playlist-container">
  <block wx:for="{{playlist}}" wx:key="_id">
    <x-playlist playlist="{{item}}"></x-playlist>
  </block>
</view>

4.組件接收頁面?zhèn)鬟f過來的數(shù)據(jù)
在組件的js文件中使用properties進行接收(需要指定所接收到的數(shù)據(jù)的類型,不指定的話會報錯)

  properties: {
    // 接收父組件傳遞的參數(shù),并規(guī)定參數(shù)的類型
    playlist: {
      type: Object
    }
  },

5.組件在wxml就可以使用接收到的數(shù)據(jù)(渲染數(shù)據(jù))
<image src="{{playlist.picUrl}}" class="playlist-img"></image>
在小程序中的背景圖片只能使用本地圖片,不允許使用網(wǎng)絡圖
如何把小圖片轉換成base64?在百度上搜索“在線制作base64”,很多網(wǎng)站都可以轉換

6.數(shù)據(jù)監(jiān)聽器observers

監(jiān)聽對象下的屬性,和接受父組件傳遞參數(shù)的properties在同一級。
['對象.屬性']
監(jiān)聽到的值不能直接用this.setData賦給對象的屬性本身,這樣會陷入數(shù)據(jù)監(jiān)聽死循環(huán)
解決方法:在組件的內部重新定義一個數(shù)據(jù)進行賦值。

  // 數(shù)據(jù)監(jiān)聽器
  observers: {
    // 監(jiān)聽對象下面的屬性
    ['playlist.playCount'](count) {
      this.setData({
        _count: this._tranNumber(count, 2)
      })
    }
  },

巧妙的去除數(shù)字后面的小數(shù)點
let numStr = num.toString().split('.')[0]
小程序對于wx:for循環(huán)提供了一個wx:key=“*this”,其中*this代表的就是元素本身=====>對于循環(huán)的純數(shù)組而言,如果循環(huán)的是對象數(shù)組,則可以直接綁定對象中的唯一屬性,如id,在不寫別名的情況下,小程序會自動識別循環(huán)的每個對象下的id屬性,并且進行綁定。
注意:在循環(huán)出來的對象不會動態(tài)變化的情況下,key值可以綁定的隨意些,否則必須要綁定足夠有辨識度的唯一標識,否則小程序無法識別元素的動態(tài)變化。

7.異步操作解決方案

傳統(tǒng)的回調地獄式異步編程寫法:

setTimeout(() => {
  console.log(1)
  setTimeout(() => {
    console.log(2)
    setTimeout(() => {
      console.log(3)
    }, 3000);
  }, 2000);
}, 1000);

promise是es6的異步操作解決方案,字面意思就是承諾,promise有三個狀態(tài),pending代表等待,fulfilled代表成功,rejected代表失敗,狀態(tài)一旦改變,則無法回退。
上面的異步操作的promise版本寫法

new Promise((resolve,reject)=>{
  setTimeout(() => {
    console.log(1)
    resolve()
  }, 1000);
}).then((res)=>{
  setTimeout(() => {
    console.log(2)
    resolve()
  }, 2000);
}).then((res)=>{
  setTimeout(() => {
    console.log(3)
    resolve()
  }, 3000);
})

8.小程序中怎樣使用async函數(shù)

es7的異步操作解決方案:async和await
云函數(shù)默認支持es7語法,但是小程序開發(fā)環(huán)境還不行,所以要想在小程序端歡快的使用es7語法,則首先需要解決環(huán)境問題。
把 regenerator/runtime.js 文件引用到有使用 async/await 的文件當中。
import regeneratorRuntime from '../../utils/runtime.js'
注意:regeneratorRuntime必須叫這個名字,不能自定義
普通函數(shù)沒有寫renturn則沒有返回值,而async函數(shù)的返回值是一個promise對象

onLoad:function(options){
    this.foo()
}
async foo(){
    console.log('foo')
    //await一定要async函數(shù)里面才能發(fā)揮正常作用
    let res = await this.timeout()
    console.log(res)
},
timeout(){
    return new Promise((resolve,reject) => {
        setTimeout(()=>{
            console.log(1)
            resolve('resolved')
        },1000)
    })
}

執(zhí)行結果
foo
1
resolved

9.第一個云函數(shù)getPlaylist

getPlaylist這個云函數(shù)我們首先需要安裝三個依賴,發(fā)請求拿數(shù)據(jù)用的
在cloudfunctions文件夾中新建一個getPlaylist文件夾,然后在這個文件夾下打開終端命令行工具,輸入npm init -y將getPlaylist初始化為一個npm管理下的項目,然后一次安裝下面這三個依賴

npm install --save request
npm install --save request-promise
npm install --save wx-server-sdk@latest

在getPlaylist文件夾下引入
const rp = require('request-promise')
然后開始寫發(fā)請求的代碼

exports.main = async(event, context) => {
  const playlist = await rp(URL).then((res) => {
    return JSON.parse(res).result
  })
}

如果要在云函數(shù)中打印一些數(shù)據(jù)用來調試,但是這個打印信息不會顯示在調試器中,因為調試器屬于前端工具,而云函數(shù)屬于后端部分的代碼。所以我們可以先上傳并部署:云端安裝依賴(不上傳node_modules)
云函數(shù)調試位置:云開發(fā)=》云函數(shù)=》云端測試,當前這個請求不需要參數(shù),把默認的參數(shù)清空,然后“運行測試”就可以在下面看到測試的結果了。
返回結果是null是因為當前的getPlaylist云函數(shù)并沒有寫返回值。
注意:在云函數(shù)中的任何一處修改要想生效 都需要進行上傳和部署。

至此,我們已經(jīng)在云函數(shù)中拿到了想要的歌單信息數(shù)據(jù)playlist ,接下來要把這個數(shù)據(jù)插入到數(shù)據(jù)庫中,首先需要在數(shù)據(jù)庫中“創(chuàng)建集合”,集合名稱定義為playlist,往數(shù)據(jù)庫中插入數(shù)據(jù)只能一條一條的插入。

10.云函數(shù)往數(shù)據(jù)庫插入不重復的數(shù)據(jù)

給數(shù)據(jù)庫插入信息之前需要先在getPlaylist云函數(shù)中初始化數(shù)據(jù)庫
const db = cloud.database()
接下來調用數(shù)據(jù)庫,往playlist集合中插入數(shù)據(jù),并且同時插入一個cerateTime字段,記錄數(shù)據(jù)產(chǎn)生的時間。
serverDate獲取當前服務器的時間

  for (let i = 0,len = playlist; i < len; i++) {
    await db.collection('playlist').add({
      data: {
        ...playlist[i],
        createTime: db.serverDate(),
      }
    }).then((res) => {
      console.log('插入成功')
    }).catch((err) => {
      console.error('插入失敗')
    })
  }

上面這段代碼有一個明顯的問題,那就是當多次讀取數(shù)據(jù)的時候,重復的歌單信息就會被多次添加,所以每次讀取歌單信息都應該和數(shù)據(jù)庫當前已有的歌單信息進行對比,相同的信息不會被重復添加。

首先定義一個list,先獲取歌單信息已有的信息,存儲在list變量中
const list = await db.collection('playlist').get()
然后將list和playlist對比去重,將不重復的數(shù)據(jù)放置到newData變量中。
定義一個flag,true代表默認的“不重復”

  const newData = []
  for (let i = 0, len1 = playlist.length; i < len1; i++) {
    let flag = true
    for (let j = 0, len2 = list.data.length; j < len2; j++) {
      if (playlist[i].id === list.data[j].id) {
        flag = false
        break
      }
    }
    if (flag) {
      newData.push(playlist[i])
    }
  }

這樣一開始插入的數(shù)據(jù)也要從playlist變?yōu)楝F(xiàn)在的不重復數(shù)據(jù)形成的數(shù)組newData

11.云函數(shù)獲取數(shù)據(jù)庫中的大于100條的數(shù)據(jù)

現(xiàn)在還遺留一個問題就是在云函數(shù)中獲取數(shù)據(jù)中的信息,只能獲取100條,在小程序代碼中最多只能獲取到20條。所以現(xiàn)在我們需要突破100條這個限制。
解決思路:假如有210條數(shù)據(jù),分三次請求,最后再把這三次請求拿到的數(shù)據(jù)進行匯總,就可以獲得全部的數(shù)據(jù)。
全部數(shù)據(jù)list不能通過const list = await db.collection('playlist').get()簡單獲得,需要進行下面的優(yōu)化:
首先需要獲得當前數(shù)據(jù)總的條數(shù)
const countResult = await db.collection('playlist').count()
countResult拿到的是一個對象,其中的total屬性對應的數(shù)據(jù)的數(shù)量。
·const total = countResult.total·
定義每次取數(shù)據(jù)的數(shù)量
const MAX_LIMIT = 100
求出應該取幾次數(shù)據(jù)
const batchTimes = Math.ceil(total / MAX_LIMIT)
需要等待幾次拿數(shù)據(jù)的請求完成完成后才能拼裝出真正完整的數(shù)據(jù)。

  const tasks = []
  for (let i = 0; i < batchTimes; i++) {
    let promise = db.collection('playlist').skip(i * MAX_LIMIT).limit(MAX_LIMIT).get()
    tasks.push(promise)
  }
  let list = {
    data: []
  }
  if (tasks.length > 0) {
    list = (await Promise.all(tasks)).reduce((acc, cur) => {
      return {
        data: acc.data.concat(cur.data)
      }
    })

  }

剛才所寫的從指定的音樂接口拿數(shù)據(jù),然后將數(shù)據(jù)插入數(shù)據(jù)庫的操作,我們希望能夠在云函數(shù)中定時自動觸發(fā)。
需要在對應的云函數(shù)文件夾中新建一個config.json文件

配置好之后一定要右鍵云函數(shù)文件夾,“上傳觸發(fā)器”,這樣觸發(fā)器才能生效。
config.json文件名是規(guī)定好的,不能改。myTrigger是自定義的觸發(fā)器名稱。

{
  "triggers":[
    {
      "name":"myTrigger",
      "type":"timer",
      "config":"0 0 10,14,16,23 * * * *"
    }
  ]
}

12.小程序端調用云函數(shù)

接下來就是小程序端讀取數(shù)據(jù),并且把數(shù)據(jù)渲染到頁面上。
我們新創(chuàng)建一個music云函數(shù)“新建Nodejs云函數(shù)”,然后在這個music云函數(shù)中寫調用數(shù)據(jù)庫,獲取數(shù)據(jù)的邏輯代碼。
skip和limit方便我們獲取指定條數(shù)的數(shù)據(jù)以及進行分頁。
orderBy表示排序,第一個參數(shù)是排序依據(jù)的字段名稱,第二個參數(shù)‘desc’代表逆序。

return await cloud.database()
    .collection('playlist')
    .skip(event.start).limit(event.count)
    .orderBy('createTime','desc')
    .get().then((res)=>{return res})

接下來在小程序界面的js文件中請求云函數(shù)music,取第0-15條數(shù)據(jù)

wx.cloud.callFunction({
   name:'music',
   data:{
     start:0,
     count:15
   }
}).then((res) => {
      this.setData({
        playlist: this.data.playlist.concat(res.result.data)
      })
      wx.stopPullDownRefresh()
    })

如果實現(xiàn)觸底下拉,請求更多15條的歌單信息?
微信自帶onReachBottom屬性,監(jiān)聽頁面觸底,我們把剛才請求歌單的方法進行一下優(yōu)化,并封裝在_getPlaylist方法中,當觸底時自動觸發(fā),并將請求的新數(shù)據(jù)拼接給playlist鼻變量。

  _getPlaylist() {
    wx.showLoading({
      title: '加載中',
    })
    wx.cloud.callFunction({
      name: 'music',
      data: {
        start: this.data.playlist.length,
        count: MAX_LIMIT,
        $url:'playlist'
      }
    }).then((res) => {
      this.setData({
        playlist: this.data.playlist.concat(res.result.data)
      })
      wx.stopPullDownRefresh()
      wx.hideLoading()
    })
  }

調用云函數(shù)的data參數(shù)中的$url:'playlist'代表要調用的對應云函數(shù)中對應的router
當用戶下拉整個頁面的時候,怎么實現(xiàn)頁面刷新,并重置當前已加載的歌單信息數(shù)據(jù)?
在當前頁面的json文件中增加屬性"enablePullDownRefresh":true,這代表允許當前頁面下拉刷新,同時在頁面的js文件中有一個onPullDownRefresh屬性,是監(jiān)聽用戶下拉動作的

  onPullDownRefresh: function() {
    this.setData({
      playlist:[]
    })
    this._getPlaylist()
  },

微信暫時無法知道用戶的下拉動作是什么時候結束的,所以可以在請求數(shù)據(jù)結束的時候增加wx.stopPullDownRefresh()用來停止下拉刷新的動畫。

13.tcb-router

一個用戶在一個云環(huán)境中只能創(chuàng)建50個云函數(shù)
相似的請求歸類到同一個云函數(shù)處理
tcb-router是一個koa風格的小程序云開發(fā)云函數(shù)輕量級類路由庫,主要用于優(yōu)化服務端函數(shù)處理邏輯。
在對應的云函數(shù)中進行安裝
npm install --save tcb-router
在對應的云函數(shù)的js文件中引用
const TcbRouter = require('tcb-router')
在云函數(shù)的js文件中的入口函數(shù)中進行使用,app可以創(chuàng)建當前TcbRouter服務,這樣TcbRouter就會自動的處理event參數(shù)和路由轉發(fā),在結束的時候別忘了通過app.serve()把當前的服務返回。
···
exports.main = async(event, context) => {
const app = new TcbRouter({
event
})
return app.serve()
}
···
用ctx.body把數(shù)據(jù)返回給小程序端

  app.router('playlist', async(ctx, next) => {
    ctx.body = await cloud.database().collection('playlist')
      .skip(event.start)
      .limit(event.count)
      .orderBy('creatTime', 'desc')
      .get()
      .then((res) => {
        return res
      })
  })

小程序端在調用云函數(shù)時,還要在data中增加一個屬性
`$url:'xxx``
xxx對應的是name對應云函數(shù)中詳細的路由。

頁面之間的跳轉

wx.navigateTo({
    url:`../../pages/musiclist/musiclist?playlistid=${this.properties.playlist.id}`,
})

上面的properties寫成data貌似也不會有什么問題。
這里問號后面的動態(tài)路由是要告訴musiclist頁面我要進入的是哪一個歌單,
musiclist頁面的onload生命周期函數(shù)中的options就可以獲取到這個傳遞過來的數(shù)據(jù),然后依據(jù)這個id去調用云函數(shù),獲取對應歌單的歌曲列表。

  onLoad: function(options) {
    console.log(options)
    wx.showLoading({
      title: '加載中',
    })
    wx.cloud.callFunction({
      name: 'music',
      data: {
        playlistid: options.playlistid,
        $url: 'musiclist'
      }
    }).then((res) => {
      console.log(res)
      const pl = res.result.playlist
      this.setData({
        musiclist: pl.tracks,
        listInfo: {
          coverImgUrl: pl.coverImgUrl,
          name: pl.name,
        }
      })
      this._setMuscilist()
      wx.hideLoading()
    })
  },

當小程序開發(fā)的頁面層級比較多的時候,每次保存都會讓小程序從主頁開始,這樣很不方便,可以在上方的編譯模式中新建一個編譯模式,啟動頁面定位為想要的頁面,另外比如有啟動參數(shù),則需要填寫上,如playlistId = 28171112148

實現(xiàn)循環(huán)的歌曲列表,當前點擊的歌曲動態(tài)添加playing高亮樣式。
在小程序中,所有自定義的屬性都用data-開頭

<block wx:for="{{musiclist}}" wx:key="id">
  <view class="musiclist-container {{item.id===playingId?'playing':''}}" bind:tap="onSelect" data-musicid="{{item.id}}" data-index="{{index}}">
  </view>
</block>

實現(xiàn)原理:如果當前點擊事件觸發(fā)的歌曲id,和自定義屬性musicid是相等的,則可以判定當前歌曲為用戶點擊的。
點擊觸發(fā)的onSelect事件,當前點擊事件的event參數(shù)有兩個屬性,一個是target,另一個是currentTarget,而綁定的自定義屬性是在currentTarget上面。原因如下:
關于事件的幾個要素:

  • 事件源,觸發(fā)事件的真正的元素
  • 事件處理函數(shù)
  • 事件對象,事件處理函數(shù)的默認參數(shù)event,event中有target屬性和currentTarget屬性,target對應的是事件源,currentTarget指的是綁定事件的元素
  • 事件類型
    onSelect(event) {
      const musicid = event.currentTarget.dataset.musicid
      this.setData({
        playingId: musicid
      })
      wx.navigateTo({
        url: `../../pages/player/player?musicid=${musicid}&index=${event.currentTarget.dataset.index}`,
      })
    }

小程序的自帶組件就是一些標簽,我們通過給標簽配置不同的屬性,就可以實現(xiàn)不同的效果

組件中的properties和data都是用來定義組件數(shù)據(jù)的,它們的差別:
properties:調用方傳給給組件的
data:組件內部使用的數(shù)據(jù)

14.本地數(shù)據(jù)存儲

將數(shù)據(jù)保存到storage中

wx.setStorage({
  key: 'musiclist',
  data: this.data.musiclist,
})

對于不需要進行頁面操作和顯示的數(shù)據(jù),我們可以不定義在data中,直接定義一個全局變量就行,這樣的話進行賦值也會更加的方便。
let musiclist = []
運用同步方法去給這個變量賦值,因為獲取到值需要直接進行下一步的邏輯處理
musiclist = wx.getStorageSync('musiclist')

動態(tài)的設置頁面上方的導航標題

wx.setNavigationBarTitle({
  title: music.name,
})

給容器動態(tài)綁定一個鋪滿全部的背景圖片
<view class="player-container" style="background:url({{picUrl}}) center/cover no-repeat"></view>

在項目中使用iconfont
進入官網(wǎng)iconfont.cn,將想要的圖標點擊購物車圖標=>加入購物車
新建項目=>加入項目,比如:demo,點擊fontclass =>點擊查看在線鏈接,生成代碼,會生成一個css文件的鏈接地址,可以下載到本地,然后將css文件修改成wxss文件(也可以不下載,直接拷貝鏈接中的代碼放入項目中)

此時圖標wxss文件是放在項目的根目錄下的,我們要在app.wxss文件中進行引用,然后在項目中就可以通過class進行使用。
@import "iconfont.wxss";

15.音樂播放的控制

小程序提供了一個wx.getBackgroundAudioManager()方法用來控制唯一背景音樂的播放,在要播放背景音樂的頁面的js文件首先定義一個變量,去獲取全局唯一的背景音頻管理器
const backgroundAudioManager = wx.getBackgroundAudioManager()
然后通過給backgroundAudioManager 的src屬性賦值,就可以實現(xiàn)背景音樂的額播放,同時注意,還需要同時設置title,否則會報錯

backgroundAudioManager.src = JSON.parse(res.result).data[0].url
backgroundAudioManager.title = music.name

如果需要在任何界面都可以聽到這個背景音樂,則需要在app.json中配置(和pages同級)

"requireBackgroundModes":[
    "audio"
],

同時還可以通過為頁面下方的mini播放器設置圖片、歌手和專輯名稱

backgroundAudioManager.coverImgUrl = music.al.picUrl
backgroundAudioManager.singer = music.ar[0].name
backgroundAudioManager.epname = music.al.name

背景音樂的暫停
backgroundAudioManager.pause()
背景音樂的播放
backgroundAudioManager.play()

在css中,animation-play-state: paused;可以讓動畫停在當前那一幀,只需要動態(tài)的給做動畫的元素添加上這個屬性,就可以實現(xiàn)動畫播放的開始與暫停

backgroundAudioManager.duration=>獲取當前背景音樂的時長,但是有時候獲取到的是underfined,解決辦法:

if(backgroundAudioManager.duration == undefined)
    //上面這樣樣判定是不合理的,因為null==undefined也會是true
if(typepf backgroundAudioManager.duration != 'undefined')
    //應該像上面那樣判定

怎么動態(tài)的給data中的對象中某一個屬性賦值

this.setData({
    ['object.xxx']:'yyyyyy'
})

this.data.progress這樣給data中的數(shù)據(jù)賦值可以成功,但不會自動響應到頁面上

backgroundAudioManager有一些事件,我們需要在這些事件上綁定對應的回調函數(shù),如:
背景音樂可以播放的時候:backgroundAudioManager.onPlay
backgroundAudioManager.seek()=》重新定義當前背景音樂的正在播放的時間點,參數(shù)為要跳轉的秒

子組件激活父元素的事件
this.triggerEvent('musicEnd')
父組件在調用子組件的標簽中進行接收,同時接收到響應后去觸發(fā)自身的onNext事件
<x-progress-bar bind:musicEnd="onNext"></x-progress-bar>

進度條的拖拽事件和backgroundAudioManager.onTimeUpdate事件是不能同時進行的,否則會造成拖拽的時候進度條會一直閃的畫面,這里的解決辦法是設置一個鎖:isMoving
當拖拽開始的時候isMoving = true
拖拽結束的時候isMoving = false
當isMoving = false的時候,onTimeUpdate里面的代碼才去執(zhí)行。

小程序控制組件的顯示與隱藏
hidden="{{flag}}" //flag為true時隱藏,為false顯示

接收父組件傳遞過來的數(shù)據(jù),如果接收的數(shù)據(jù),這個數(shù)據(jù)除了類型,還有其他的屬性,則需要寫成對象的形式,如果只需要聲明一個類型,則可以不用對象的形式

  properties: {
    isLyricShow: {
      type: Boolean,
      value: false
    },
    lyric: String
  },

16.如何實現(xiàn)組件間傳值

自組件給父組件傳值:
自組件:

this.triggerEvent('timeUpdata',{
   currentTime
})

調用這個子組件的父組件的頁面上對應的標簽
<x-process-bar bind:musicEnd="onNext" bind:timeUpdate="timeUpdata"></x-process-bar>
父組件通過觸發(fā)自定義事件接受到這個數(shù)據(jù)currentTime的同時想傳遞給另一個子組件,
通過定義事件處理函數(shù),通過給另一個需要接收數(shù)據(jù)的子組件標簽上起名一個class

  timeUpdata(event){
    this.selectComponent('.lyric').update(event.detail.currentTime)
  },

這樣的話,另一個子組件就可以通過自身的update事件,成功接收到currentTime這個數(shù)據(jù)了。
注意:這時候子組件的update事件相當于被父組件給調用了一次。

歌詞的滾動是利用了<scroll-view>組件,scroll-top屬性可以規(guī)定這個容器里的內容向上滾動的距離,scroll-y屬性表示上下方向的滾動,scroll-with-animatio="true"表示開啟滾動過渡動畫。

scroll-top的屬性值只能是px,而我們設置的歌詞單行高度是64rpx,不同手機這個rpx代表的實際尺寸都不同,所有這里需要進行一個換算

lifetimes: {
  ready() {
    wx.getSystemInfo({
      success: function(res) {
        lyricHeight = res.screenWidth / 750 * 64
      },
    })
  }
},

小程序寬度是750rpx,把屏幕的寬度除以750,得到的就是1rpx

17.給小程序設置全局屬性和方法

app.js中的

    this.globalData = {
      playingMusicId:-1
    }
  },
  setPlayMusicId(musicId){
    this.globalData.playingMusicId = musicId
  },
  getPlayMusicId(){
    return this.globalData.playingMusicId
  }

在頁面獲取全局的屬性或者方法

const app =getApp()
//在播放的音樂的方法中設置屬性
app.setPlayMusicId(musicid)

在對應的組件的頁面生命周期中,當頁面展示的時候,去觸發(fā)方法獲取到全局變量

pageLifetimes: {
  show() {
    this.setData({
      playingId: parseInt(app.getPlayMusicId())
    })
  }
},

小程序下方自帶的mini控制面板的暫停和播放對應的也就是背景音樂監(jiān)聽事件中的onPause和onPlay
backgroundAudioManager.onPlaybackgroundAudioManager.onPause

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 最近從1月25日到2月8日的兩周之內抽空編寫了 小打卡 微信小程序,該產(chǎn)品主要是針對每日早起、健身、閱讀等習慣進行...
    徐佳義閱讀 14,665評論 10 120
  • 子曰:“朝聞道,夕死可矣?!?孔子講:“如果早上能夠知曉了大道,晚上死掉也是心甘的?!?大道到底是什么?我想應該是...
    哈皮波閱讀 795評論 0 0
  • 知行格-英雄之旅 日精進第 14 日 日閱讀:《看見》九十章 日鍛煉:走了好多路,還沖了個次(跟舍友出去浪,到處逛...
    巖松不姓李不姓白閱讀 250評論 0 2
  • 是春天的第一縷風 把枝頭含苞待放的那一枚火種點燃 一朵紅色的火焰燃起來了 風剛一張口輕輕一吹 又一朵紅色的火焰燃起...
    指尖蝶舞的花園閱讀 319評論 0 4
  • 素未謀面的你 漸漸駛入內心深處 笑淚、喜悲 與你共享人生百味 許久未見 每次 你的名字都會在我心中泛起漣漪 可回憶...
    我和你的青空下閱讀 203評論 0 3

友情鏈接更多精彩內容