本文目錄:
- 1.云開發(fā)的優(yōu)勢(shì)
- 2.云開發(fā)的五大基礎(chǔ)能力
- 3.基本結(jié)構(gòu)分析:
- 4.寫輪播圖
- 5.組件化開發(fā)流程
- 6.數(shù)據(jù)監(jiān)聽器observers
- 7.異步操作解決方案
- 8.小程序中怎樣使用async函數(shù)
- 9.第一個(gè)云函數(shù)getPlaylist
- 10.小程序端調(diào)用云函數(shù)
- 11.云函數(shù)獲取數(shù)據(jù)庫(kù)中的大于100條的數(shù)據(jù)
- 12.小程序端調(diào)用云函數(shù)
- 13.tcb-router
- 14.本地?cái)?shù)據(jù)存儲(chǔ)
- 15.音樂播放的控制
- 16.如何實(shí)現(xiàn)組件間傳值
- 17.給小程序設(shè)置全局屬性和方法
1.云開發(fā)的優(yōu)勢(shì)
正常的開發(fā)分為前端和后端
傳統(tǒng)的小程序開發(fā)完成之后需要進(jìn)行一個(gè)上線部署,而傳統(tǒng)部署的基本步驟有:購(gòu)買服務(wù)器、域名,備案,網(wǎng)絡(luò)防護(hù),負(fù)載均衡,監(jiān)控警告等。這些事情非常的繁瑣,讓人頭疼。

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

serverless=》無服務(wù)開發(fā)=》小程序的云開發(fā)
在云開發(fā)的核心理念中,函數(shù)即服務(wù),依托騰訊端提供的后端服務(wù),我們通過函數(shù)就可以實(shí)現(xiàn)調(diào)用,從而實(shí)現(xiàn)serverless
2.云開發(fā)的五大基礎(chǔ)能力
- 1.云函數(shù):在云端運(yùn)行代碼,并且具有天然的鑒權(quán)機(jī)制。
- 2.云數(shù)據(jù)庫(kù):既可以在云函數(shù)端操作,又可以在小程序端操作的非關(guān)系型json數(shù)據(jù)庫(kù)(類似moongodb)
- 3.云調(diào)用:基于云函數(shù)免鑒權(quán)使用小程序開放接口的能力
- 4.HTTP API:可以讓第三方服務(wù)很方便的在已有服務(wù)器上訪問云資源,實(shí)現(xiàn)與云開發(fā)的互通。
- 5.云存儲(chǔ):在云端存儲(chǔ)文件,可以在云端控制臺(tái)可視化管理
我們可以通過云函數(shù)去定期的去第三方數(shù)據(jù)服務(wù)器拿數(shù)據(jù),然后更新到云數(shù)據(jù)庫(kù)中
1.什么是小程序的云開發(fā)?
傳統(tǒng)模式:小程序端展現(xiàn)的數(shù)據(jù)是發(fā)請(qǐng)求給后端拿到的
云開發(fā)模式:小程序端提供的原生接口可以直接去操作遠(yuǎn)程的云數(shù)據(jù)庫(kù),云函數(shù),云存儲(chǔ)。而我們根本根本不知道后端部署在那里。
2.什么是serverless?
打破前端和后端的物理隔離
當(dāng)我們使用后端服務(wù)的時(shí)候,不需要關(guān)注后端的ip地址是什么等等
在小程序官網(wǎng)上注冊(cè)賬號(hào),然后下載開發(fā)者工具,打開開發(fā)者工具,創(chuàng)建一個(gè)新項(xiàng)目。
需要注意一點(diǎn),APPID是每一個(gè)小程序的唯一標(biāo)識(shí),這個(gè)ID在官網(wǎng)賬號(hào)中的“開發(fā)”界面可以查看到。
進(jìn)入項(xiàng)目之后,第一次使用云開發(fā)的用戶需要點(diǎn)擊界面上方的“云開發(fā)”按鈕去開通服務(wù)。
首先可以選擇創(chuàng)建一個(gè)test作為開發(fā)環(huán)境的云服務(wù),等到項(xiàng)目上線再創(chuàng)建一個(gè)生產(chǎn)環(huán)境進(jìn)行使用。
3.基本結(jié)構(gòu)分析:
cloudfunctions=》云函數(shù)部分
miniprogram=》前端部分代碼
- images圖片資源
- pages創(chuàng)建小程序的時(shí)候自帶文件夾和文件(可以全部刪除)
- style創(chuàng)建小程序的時(shí)候自帶樣式(可以全部刪除)

app.js全局js文件
onLaunch:function(){}
當(dāng)小程序啟動(dòng)的時(shí)候觸發(fā)的鉤子函數(shù)
wx.cloud.init({ env:"在此處填入環(huán)境ID",
這個(gè)地方填入的是哪個(gè)ID,小程序自動(dòng)連接的就是對(duì)應(yīng)的環(huán)境,先填開發(fā)環(huán)境,上線的時(shí)候把這個(gè)地方改成生產(chǎn)環(huán)境就可以了。
traceUser: true
設(shè)置為true的時(shí)候,每一個(gè)訪問過我們的小程序的用戶都會(huì)被記錄,并且以倒序的順序進(jìn)行顯示
})
app.json全局配置文件
pages
//文件的路徑
window
//窗口的一些配置(頁面的最上方)
“sitemapLocation”:sitemap.json
//小程序開放的內(nèi)部搜索,對(duì)應(yīng)的配置文件sitemap.json,決定了我們的小程序界面是否能被搜索到,在小程序優(yōu)化中可以用到
tabBar
//小程序封裝的一個(gè)對(duì)象,有color,selectedColor,list等常用屬性。
//對(duì)應(yīng)的小程序頁面下方的導(dǎo)航,最少兩個(gè),最多五個(gè)
app.wxss全局樣式
README.md小程序的開發(fā)說明
project.config小程序項(xiàng)目的配置文件,突出為整個(gè)項(xiàng)目
iconfont下載圖標(biāo)很方便,可以自由選擇格式,大小,以及顏色(點(diǎn)擊下載,直接下載到本地就可以直接使用了)
把style文件夾中的guide.wxss和app.wxss中的小程序自帶樣式都去除掉,樣式都是我們自定義
寫最初的幾個(gè)主頁面:
先在app.json中的“pages”中把框架自帶的頁面全部刪除,然后加上自己要寫的幾個(gè)頁面路徑,保存之后在對(duì)應(yīng)的路徑就會(huì)自動(dòng)生成頁面文件。(手動(dòng)把框架自帶的頁面文件刪除掉)
4.寫輪播圖
小程序原生自帶swiper組件,里面的項(xiàng)目swiper-item,在swiper-item里放image標(biāo)簽
小程序自帶的block標(biāo)簽,建議把wx:for寫在block上面,block不會(huì)真實(shí)渲染,在輪播圖這里我們?cè)趕wiper-item外面包裹一層block,然后wx:for渲染寫在block標(biāo)簽上
swiper的常用屬性:
- indicator-dots="true",顯示導(dǎo)航的小點(diǎn),默認(rèn)為flase
- autoplay=“true”自動(dòng)播放
- interval=“2000”自動(dòng)播放的間隔是2000ms
- duration=”1000“滑動(dòng)播放時(shí)長(zhǎng)為1000ms
小程序自帶的image標(biāo)簽的常用屬性
- mode=”scaleToFill“,保證圖片完全覆蓋當(dāng)前image容器,這種縮放模式下圖片非常有可能會(huì)產(chǎn)生變形,實(shí)際效果不好
- mode=”aspectFit“,讓圖片能夠完整的顯示在容器中,缺點(diǎn)是有可能會(huì)讓容器留白
- mode=”widthFix“,讓圖片能夠完全覆蓋容器,同時(shí)保持圖片的寬高比不變,同時(shí)給image標(biāo)簽增加width100%height100%的樣式,保證image能夠完整覆蓋父元素。這個(gè)縮放模式是實(shí)際項(xiàng)目中最常用的。
5.組件化開發(fā)流程
組件:在用戶界面開發(fā)領(lǐng)域,組件是一種面向用戶的,獨(dú)立的,可復(fù)用的交互元素的封裝。
組件的組成:
結(jié)構(gòu)=》wxml
邏輯=》js
樣式=》wxss
組件的設(shè)計(jì)原理:高內(nèi)聚,低耦合,單一職責(zé),避免過多參數(shù)
封裝第一個(gè)組件:歌曲列表組件
1.創(chuàng)建
首先在項(xiàng)目的miniprogram文件夾下新建一個(gè)文件夾components,然后在components中右鍵創(chuàng)建對(duì)應(yīng)的組件(這里是playlist)
2.在頁面中引用和使用
在頁面的json中進(jìn)行引用
{
"usingComponents": {
"x-playlist": "/components/playlist/playlist"
},
"enablePullDownRefresh":true
}
在頁面的wxml中進(jìn)行使用
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進(jìn)行接收(需要指定所接收到的數(shù)據(jù)的類型,不指定的話會(huì)報(bào)錯(cuò))
properties: {
// 接收父組件傳遞的參數(shù),并規(guī)定參數(shù)的類型
playlist: {
type: Object
}
},
5.組件在wxml就可以使用接收到的數(shù)據(jù)(渲染數(shù)據(jù))
<image src="{{playlist.picUrl}}" class="playlist-img"></image>
在小程序中的背景圖片只能使用本地圖片,不允許使用網(wǎng)絡(luò)圖
如何把小圖片轉(zhuǎn)換成base64?在百度上搜索“在線制作base64”,很多網(wǎng)站都可以轉(zhuǎn)換
6.數(shù)據(jù)監(jiān)聽器observers
監(jiān)聽對(duì)象下的屬性,和接受父組件傳遞參數(shù)的properties在同一級(jí)。
['對(duì)象.屬性']
監(jiān)聽到的值不能直接用this.setData賦給對(duì)象的屬性本身,這樣會(huì)陷入數(shù)據(jù)監(jiān)聽死循環(huán)
解決方法:在組件的內(nèi)部重新定義一個(gè)數(shù)據(jù)進(jìn)行賦值。
// 數(shù)據(jù)監(jiān)聽器
observers: {
// 監(jiān)聽對(duì)象下面的屬性
['playlist.playCount'](count) {
this.setData({
_count: this._tranNumber(count, 2)
})
}
},
巧妙的去除數(shù)字后面的小數(shù)點(diǎn)
let numStr = num.toString().split('.')[0]
小程序?qū)τ趙x:for循環(huán)提供了一個(gè)wx:key=“*this”,其中*this代表的就是元素本身=====>對(duì)于循環(huán)的純數(shù)組而言,如果循環(huán)的是對(duì)象數(shù)組,則可以直接綁定對(duì)象中的唯一屬性,如id,在不寫別名的情況下,小程序會(huì)自動(dòng)識(shí)別循環(huán)的每個(gè)對(duì)象下的id屬性,并且進(jìn)行綁定。
注意:在循環(huán)出來的對(duì)象不會(huì)動(dòng)態(tài)變化的情況下,key值可以綁定的隨意些,否則必須要綁定足夠有辨識(shí)度的唯一標(biāo)識(shí),否則小程序無法識(shí)別元素的動(dòng)態(tài)變化。
7.異步操作解決方案
傳統(tǒng)的回調(diào)地獄式異步編程寫法:
setTimeout(() => {
console.log(1)
setTimeout(() => {
console.log(2)
setTimeout(() => {
console.log(3)
}, 3000);
}, 2000);
}, 1000);
promise是es6的異步操作解決方案,字面意思就是承諾,promise有三個(gè)狀態(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ù)默認(rèn)支持es7語法,但是小程序開發(fā)環(huán)境還不行,所以要想在小程序端歡快的使用es7語法,則首先需要解決環(huán)境問題。
把 regenerator/runtime.js 文件引用到有使用 async/await 的文件當(dāng)中。
import regeneratorRuntime from '../../utils/runtime.js'
注意:regeneratorRuntime必須叫這個(gè)名字,不能自定義
普通函數(shù)沒有寫renturn則沒有返回值,而async函數(shù)的返回值是一個(gè)promise對(duì)象
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í)行結(jié)果
foo
1
resolved
9.第一個(gè)云函數(shù)getPlaylist
getPlaylist這個(gè)云函數(shù)我們首先需要安裝三個(gè)依賴,發(fā)請(qǐng)求拿數(shù)據(jù)用的
在cloudfunctions文件夾中新建一個(gè)getPlaylist文件夾,然后在這個(gè)文件夾下打開終端命令行工具,輸入npm init -y將getPlaylist初始化為一個(gè)npm管理下的項(xiàng)目,然后一次安裝下面這三個(gè)依賴
npm install --save request
npm install --save request-promise
npm install --save wx-server-sdk@latest
在getPlaylist文件夾下引入
const rp = require('request-promise')
然后開始寫發(fā)請(qǐng)求的代碼
exports.main = async(event, context) => {
const playlist = await rp(URL).then((res) => {
return JSON.parse(res).result
})
}
如果要在云函數(shù)中打印一些數(shù)據(jù)用來調(diào)試,但是這個(gè)打印信息不會(huì)顯示在調(diào)試器中,因?yàn)檎{(diào)試器屬于前端工具,而云函數(shù)屬于后端部分的代碼。所以我們可以先上傳并部署:云端安裝依賴(不上傳node_modules)
云函數(shù)調(diào)試位置:云開發(fā)=》云函數(shù)=》云端測(cè)試,當(dāng)前這個(gè)請(qǐng)求不需要參數(shù),把默認(rèn)的參數(shù)清空,然后“運(yùn)行測(cè)試”就可以在下面看到測(cè)試的結(jié)果了。
返回結(jié)果是null是因?yàn)楫?dāng)前的getPlaylist云函數(shù)并沒有寫返回值。
注意:在云函數(shù)中的任何一處修改要想生效 都需要進(jìn)行上傳和部署。
至此,我們已經(jīng)在云函數(shù)中拿到了想要的歌單信息數(shù)據(jù)playlist ,接下來要把這個(gè)數(shù)據(jù)插入到數(shù)據(jù)庫(kù)中,首先需要在數(shù)據(jù)庫(kù)中“創(chuàng)建集合”,集合名稱定義為playlist,往數(shù)據(jù)庫(kù)中插入數(shù)據(jù)只能一條一條的插入。
10.云函數(shù)往數(shù)據(jù)庫(kù)插入不重復(fù)的數(shù)據(jù)
給數(shù)據(jù)庫(kù)插入信息之前需要先在getPlaylist云函數(shù)中初始化數(shù)據(jù)庫(kù)
const db = cloud.database()
接下來調(diào)用數(shù)據(jù)庫(kù),往playlist集合中插入數(shù)據(jù),并且同時(shí)插入一個(gè)cerateTime字段,記錄數(shù)據(jù)產(chǎn)生的時(shí)間。
serverDate獲取當(dāng)前服務(wù)器的時(shí)間
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('插入失敗')
})
}
上面這段代碼有一個(gè)明顯的問題,那就是當(dāng)多次讀取數(shù)據(jù)的時(shí)候,重復(fù)的歌單信息就會(huì)被多次添加,所以每次讀取歌單信息都應(yīng)該和數(shù)據(jù)庫(kù)當(dāng)前已有的歌單信息進(jìn)行對(duì)比,相同的信息不會(huì)被重復(fù)添加。
首先定義一個(gè)list,先獲取歌單信息已有的信息,存儲(chǔ)在list變量中
const list = await db.collection('playlist').get()
然后將list和playlist對(duì)比去重,將不重復(fù)的數(shù)據(jù)放置到newData變量中。
定義一個(gè)flag,true代表默認(rèn)的“不重復(fù)”
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)在的不重復(fù)數(shù)據(jù)形成的數(shù)組newData
11.云函數(shù)獲取數(shù)據(jù)庫(kù)中的大于100條的數(shù)據(jù)
現(xiàn)在還遺留一個(gè)問題就是在云函數(shù)中獲取數(shù)據(jù)中的信息,只能獲取100條,在小程序代碼中最多只能獲取到20條。所以現(xiàn)在我們需要突破100條這個(gè)限制。
解決思路:假如有210條數(shù)據(jù),分三次請(qǐng)求,最后再把這三次請(qǐng)求拿到的數(shù)據(jù)進(jìn)行匯總,就可以獲得全部的數(shù)據(jù)。
全部數(shù)據(jù)list不能通過const list = await db.collection('playlist').get()簡(jiǎn)單獲得,需要進(jìn)行下面的優(yōu)化:
首先需要獲得當(dāng)前數(shù)據(jù)總的條數(shù)
const countResult = await db.collection('playlist').count()
countResult拿到的是一個(gè)對(duì)象,其中的total屬性對(duì)應(yīng)的數(shù)據(jù)的數(shù)量。
·const total = countResult.total·
定義每次取數(shù)據(jù)的數(shù)量
const MAX_LIMIT = 100
求出應(yīng)該取幾次數(shù)據(jù)
const batchTimes = Math.ceil(total / MAX_LIMIT)
需要等待幾次拿數(shù)據(jù)的請(qǐng)求完成完成后才能拼裝出真正完整的數(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ù)庫(kù)的操作,我們希望能夠在云函數(shù)中定時(shí)自動(dòng)觸發(fā)。
需要在對(duì)應(yīng)的云函數(shù)文件夾中新建一個(gè)config.json文件
配置好之后一定要右鍵云函數(shù)文件夾,“上傳觸發(fā)器”,這樣觸發(fā)器才能生效。
config.json文件名是規(guī)定好的,不能改。myTrigger是自定義的觸發(fā)器名稱。
{
"triggers":[
{
"name":"myTrigger",
"type":"timer",
"config":"0 0 10,14,16,23 * * * *"
}
]
}
12.小程序端調(diào)用云函數(shù)
接下來就是小程序端讀取數(shù)據(jù),并且把數(shù)據(jù)渲染到頁面上。
我們新創(chuàng)建一個(gè)music云函數(shù)“新建Nodejs云函數(shù)”,然后在這個(gè)music云函數(shù)中寫調(diào)用數(shù)據(jù)庫(kù),獲取數(shù)據(jù)的邏輯代碼。
skip和limit方便我們獲取指定條數(shù)的數(shù)據(jù)以及進(jìn)行分頁。
orderBy表示排序,第一個(gè)參數(shù)是排序依據(jù)的字段名稱,第二個(gè)參數(shù)‘desc’代表逆序。
return await cloud.database()
.collection('playlist')
.skip(event.start).limit(event.count)
.orderBy('createTime','desc')
.get().then((res)=>{return res})
接下來在小程序界面的js文件中請(qǐng)求云函數(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()
})
如果實(shí)現(xiàn)觸底下拉,請(qǐng)求更多15條的歌單信息?
微信自帶onReachBottom屬性,監(jiān)聽頁面觸底,我們把剛才請(qǐng)求歌單的方法進(jìn)行一下優(yōu)化,并封裝在_getPlaylist方法中,當(dāng)觸底時(shí)自動(dòng)觸發(fā),并將請(qǐng)求的新數(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()
})
}
調(diào)用云函數(shù)的data參數(shù)中的$url:'playlist'代表要調(diào)用的對(duì)應(yīng)云函數(shù)中對(duì)應(yīng)的router
當(dāng)用戶下拉整個(gè)頁面的時(shí)候,怎么實(shí)現(xiàn)頁面刷新,并重置當(dāng)前已加載的歌單信息數(shù)據(jù)?
在當(dāng)前頁面的json文件中增加屬性"enablePullDownRefresh":true,這代表允許當(dāng)前頁面下拉刷新,同時(shí)在頁面的js文件中有一個(gè)onPullDownRefresh屬性,是監(jiān)聽用戶下拉動(dòng)作的
onPullDownRefresh: function() {
this.setData({
playlist:[]
})
this._getPlaylist()
},
微信暫時(shí)無法知道用戶的下拉動(dòng)作是什么時(shí)候結(jié)束的,所以可以在請(qǐng)求數(shù)據(jù)結(jié)束的時(shí)候增加wx.stopPullDownRefresh()用來停止下拉刷新的動(dòng)畫。
13.tcb-router
一個(gè)用戶在一個(gè)云環(huán)境中只能創(chuàng)建50個(gè)云函數(shù)
相似的請(qǐng)求歸類到同一個(gè)云函數(shù)處理
tcb-router是一個(gè)koa風(fēng)格的小程序云開發(fā)云函數(shù)輕量級(jí)類路由庫(kù),主要用于優(yōu)化服務(wù)端函數(shù)處理邏輯。
在對(duì)應(yīng)的云函數(shù)中進(jìn)行安裝
npm install --save tcb-router
在對(duì)應(yīng)的云函數(shù)的js文件中引用
const TcbRouter = require('tcb-router')
在云函數(shù)的js文件中的入口函數(shù)中進(jìn)行使用,app可以創(chuàng)建當(dāng)前TcbRouter服務(wù),這樣TcbRouter就會(huì)自動(dòng)的處理event參數(shù)和路由轉(zhuǎn)發(fā),在結(jié)束的時(shí)候別忘了通過app.serve()把當(dāng)前的服務(wù)返回。
···
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
})
})
小程序端在調(diào)用云函數(shù)時(shí),還要在data中增加一個(gè)屬性
`$url:'xxx``
xxx對(duì)應(yīng)的是name對(duì)應(yīng)云函數(shù)中詳細(xì)的路由。
頁面之間的跳轉(zhuǎn)
wx.navigateTo({
url:`../../pages/musiclist/musiclist?playlistid=${this.properties.playlist.id}`,
})
上面的properties寫成data貌似也不會(huì)有什么問題。
這里問號(hào)后面的動(dòng)態(tài)路由是要告訴musiclist頁面我要進(jìn)入的是哪一個(gè)歌單,
musiclist頁面的onload生命周期函數(shù)中的options就可以獲取到這個(gè)傳遞過來的數(shù)據(jù),然后依據(jù)這個(gè)id去調(diào)用云函數(shù),獲取對(duì)應(yīng)歌單的歌曲列表。
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()
})
},
當(dāng)小程序開發(fā)的頁面層級(jí)比較多的時(shí)候,每次保存都會(huì)讓小程序從主頁開始,這樣很不方便,可以在上方的編譯模式中新建一個(gè)編譯模式,啟動(dòng)頁面定位為想要的頁面,另外比如有啟動(dòng)參數(shù),則需要填寫上,如playlistId = 28171112148
實(shí)現(xiàn)循環(huán)的歌曲列表,當(dāng)前點(diǎn)擊的歌曲動(dòng)態(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>
實(shí)現(xiàn)原理:如果當(dāng)前點(diǎn)擊事件觸發(fā)的歌曲id,和自定義屬性musicid是相等的,則可以判定當(dāng)前歌曲為用戶點(diǎn)擊的。
點(diǎn)擊觸發(fā)的onSelect事件,當(dāng)前點(diǎn)擊事件的event參數(shù)有兩個(gè)屬性,一個(gè)是target,另一個(gè)是currentTarget,而綁定的自定義屬性是在currentTarget上面。原因如下:
關(guān)于事件的幾個(gè)要素:
- 事件源,觸發(fā)事件的真正的元素
- 事件處理函數(shù)
- 事件對(duì)象,事件處理函數(shù)的默認(rèn)參數(shù)event,event中有target屬性和currentTarget屬性,target對(duì)應(yīng)的是事件源,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}`,
})
}
小程序的自帶組件就是一些標(biāo)簽,我們通過給標(biāo)簽配置不同的屬性,就可以實(shí)現(xiàn)不同的效果
組件中的properties和data都是用來定義組件數(shù)據(jù)的,它們的差別:
properties:調(diào)用方傳給給組件的
data:組件內(nèi)部使用的數(shù)據(jù)
14.本地?cái)?shù)據(jù)存儲(chǔ)
將數(shù)據(jù)保存到storage中
wx.setStorage({
key: 'musiclist',
data: this.data.musiclist,
})
對(duì)于不需要進(jìn)行頁面操作和顯示的數(shù)據(jù),我們可以不定義在data中,直接定義一個(gè)全局變量就行,這樣的話進(jìn)行賦值也會(huì)更加的方便。
let musiclist = []
運(yùn)用同步方法去給這個(gè)變量賦值,因?yàn)楂@取到值需要直接進(jìn)行下一步的邏輯處理
musiclist = wx.getStorageSync('musiclist')
動(dòng)態(tài)的設(shè)置頁面上方的導(dǎo)航標(biāo)題
wx.setNavigationBarTitle({
title: music.name,
})
給容器動(dòng)態(tài)綁定一個(gè)鋪滿全部的背景圖片
<view class="player-container" style="background:url({{picUrl}}) center/cover no-repeat"></view>
在項(xiàng)目中使用iconfont
進(jìn)入官網(wǎng)iconfont.cn,將想要的圖標(biāo)點(diǎn)擊購(gòu)物車圖標(biāo)=>加入購(gòu)物車
新建項(xiàng)目=>加入項(xiàng)目,比如:demo,點(diǎn)擊fontclass =>點(diǎn)擊查看在線鏈接,生成代碼,會(huì)生成一個(gè)css文件的鏈接地址,可以下載到本地,然后將css文件修改成wxss文件(也可以不下載,直接拷貝鏈接中的代碼放入項(xiàng)目中)
此時(shí)圖標(biāo)wxss文件是放在項(xiàng)目的根目錄下的,我們要在app.wxss文件中進(jìn)行引用,然后在項(xiàng)目中就可以通過class進(jìn)行使用。
@import "iconfont.wxss";
15.音樂播放的控制
小程序提供了一個(gè)wx.getBackgroundAudioManager()方法用來控制唯一背景音樂的播放,在要播放背景音樂的頁面的js文件首先定義一個(gè)變量,去獲取全局唯一的背景音頻管理器
const backgroundAudioManager = wx.getBackgroundAudioManager()
然后通過給backgroundAudioManager 的src屬性賦值,就可以實(shí)現(xiàn)背景音樂的額播放,同時(shí)注意,還需要同時(shí)設(shè)置title,否則會(huì)報(bào)錯(cuò)
backgroundAudioManager.src = JSON.parse(res.result).data[0].url
backgroundAudioManager.title = music.name
如果需要在任何界面都可以聽到這個(gè)背景音樂,則需要在app.json中配置(和pages同級(jí))
"requireBackgroundModes":[
"audio"
],
同時(shí)還可以通過為頁面下方的mini播放器設(shè)置圖片、歌手和專輯名稱
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;可以讓動(dòng)畫停在當(dāng)前那一幀,只需要?jiǎng)討B(tài)的給做動(dòng)畫的元素添加上這個(gè)屬性,就可以實(shí)現(xiàn)動(dòng)畫播放的開始與暫停
backgroundAudioManager.duration=>獲取當(dāng)前背景音樂的時(shí)長(zhǎng),但是有時(shí)候獲取到的是underfined,解決辦法:
if(backgroundAudioManager.duration == undefined)
//上面這樣樣判定是不合理的,因?yàn)閚ull==undefined也會(huì)是true
if(typepf backgroundAudioManager.duration != 'undefined')
//應(yīng)該像上面那樣判定
怎么動(dòng)態(tài)的給data中的對(duì)象中某一個(gè)屬性賦值
this.setData({
['object.xxx']:'yyyyyy'
})
this.data.progress這樣給data中的數(shù)據(jù)賦值可以成功,但不會(huì)自動(dòng)響應(yīng)到頁面上
backgroundAudioManager有一些事件,我們需要在這些事件上綁定對(duì)應(yīng)的回調(diào)函數(shù),如:
背景音樂可以播放的時(shí)候:backgroundAudioManager.onPlay
backgroundAudioManager.seek()=》重新定義當(dāng)前背景音樂的正在播放的時(shí)間點(diǎn),參數(shù)為要跳轉(zhuǎn)的秒
子組件激活父元素的事件
this.triggerEvent('musicEnd')
父組件在調(diào)用子組件的標(biāo)簽中進(jìn)行接收,同時(shí)接收到響應(yīng)后去觸發(fā)自身的onNext事件
<x-progress-bar bind:musicEnd="onNext"></x-progress-bar>
進(jìn)度條的拖拽事件和backgroundAudioManager.onTimeUpdate事件是不能同時(shí)進(jìn)行的,否則會(huì)造成拖拽的時(shí)候進(jìn)度條會(huì)一直閃的畫面,這里的解決辦法是設(shè)置一個(gè)鎖:isMoving
當(dāng)拖拽開始的時(shí)候isMoving = true
拖拽結(jié)束的時(shí)候isMoving = false
當(dāng)isMoving = false的時(shí)候,onTimeUpdate里面的代碼才去執(zhí)行。
小程序控制組件的顯示與隱藏
hidden="{{flag}}" //flag為true時(shí)隱藏,為false顯示
接收父組件傳遞過來的數(shù)據(jù),如果接收的數(shù)據(jù),這個(gè)數(shù)據(jù)除了類型,還有其他的屬性,則需要寫成對(duì)象的形式,如果只需要聲明一個(gè)類型,則可以不用對(duì)象的形式
properties: {
isLyricShow: {
type: Boolean,
value: false
},
lyric: String
},
16.如何實(shí)現(xiàn)組件間傳值
自組件給父組件傳值:
自組件:
this.triggerEvent('timeUpdata',{
currentTime
})
調(diào)用這個(gè)子組件的父組件的頁面上對(duì)應(yīng)的標(biāo)簽
<x-process-bar bind:musicEnd="onNext" bind:timeUpdate="timeUpdata"></x-process-bar>
父組件通過觸發(fā)自定義事件接受到這個(gè)數(shù)據(jù)currentTime的同時(shí)想傳遞給另一個(gè)子組件,
通過定義事件處理函數(shù),通過給另一個(gè)需要接收數(shù)據(jù)的子組件標(biāo)簽上起名一個(gè)class
timeUpdata(event){
this.selectComponent('.lyric').update(event.detail.currentTime)
},
這樣的話,另一個(gè)子組件就可以通過自身的update事件,成功接收到currentTime這個(gè)數(shù)據(jù)了。
注意:這時(shí)候子組件的update事件相當(dāng)于被父組件給調(diào)用了一次。
歌詞的滾動(dòng)是利用了<scroll-view>組件,scroll-top屬性可以規(guī)定這個(gè)容器里的內(nèi)容向上滾動(dòng)的距離,scroll-y屬性表示上下方向的滾動(dòng),scroll-with-animatio="true"表示開啟滾動(dòng)過渡動(dòng)畫。
scroll-top的屬性值只能是px,而我們?cè)O(shè)置的歌詞單行高度是64rpx,不同手機(jī)這個(gè)rpx代表的實(shí)際尺寸都不同,所有這里需要進(jìn)行一個(gè)換算
lifetimes: {
ready() {
wx.getSystemInfo({
success: function(res) {
lyricHeight = res.screenWidth / 750 * 64
},
})
}
},
小程序?qū)挾仁?50rpx,把屏幕的寬度除以750,得到的就是1rpx
17.給小程序設(shè)置全局屬性和方法
app.js中的
this.globalData = {
playingMusicId:-1
}
},
setPlayMusicId(musicId){
this.globalData.playingMusicId = musicId
},
getPlayMusicId(){
return this.globalData.playingMusicId
}
在頁面獲取全局的屬性或者方法
const app =getApp()
//在播放的音樂的方法中設(shè)置屬性
app.setPlayMusicId(musicid)
在對(duì)應(yīng)的組件的頁面生命周期中,當(dāng)頁面展示的時(shí)候,去觸發(fā)方法獲取到全局變量
pageLifetimes: {
show() {
this.setData({
playingId: parseInt(app.getPlayMusicId())
})
}
},
小程序下方自帶的mini控制面板的暫停和播放對(duì)應(yīng)的也就是背景音樂監(jiān)聽事件中的onPause和onPlay
backgroundAudioManager.onPlay和backgroundAudioManager.onPause