|
小程序是通過調(diào)用 Page 函數(shù)來注冊一個(gè)頁面的:
//index.js
Page({
data: {
text: "This is page data."
},
onLoad: function(options) {
// Do some initialize when page load.
},
// Event handler.
viewTap: function() {
this.setData({
text: 'Set some data for updating view.'
}, function() {
// this is setData callback
})
}
})
復(fù)制代碼
這里 Page 的作用相當(dāng)于構(gòu)造函數(shù), Page 會(huì)初始化頁面對(duì)象(實(shí)例),然后將配置參數(shù)中的屬性 merge 到頁面對(duì)象上。 假設(shè)你封裝了個(gè) http 模塊負(fù)責(zé)發(fā)出請求,你想在頁面對(duì)象中直接通過 this.http 引用這個(gè)模塊,就需要擴(kuò)展頁面對(duì)象。要擴(kuò)展一個(gè)對(duì)象,在 JavaScript 中的常見做法是擴(kuò)展構(gòu)造函數(shù)的 prototype 屬性,這是 Vue 很多插件的實(shí)現(xiàn): import axios from 'axios' Vue.prototype.axios = axios // 在 vue 組件中 this.axios.get(api).then(callback) 復(fù)制代碼 很不幸,在小程序中這個(gè)辦法無效。 Page 并不是普通的構(gòu)造函數(shù),底層還做了很多其他事情,沒辦法直接通過 Page.prototype 擴(kuò)展頁面對(duì)象。 我們可以轉(zhuǎn)變思路,擴(kuò)展傳進(jìn) Page 的配置對(duì)象。既然始終要通過調(diào)用 Page 注冊頁面,可以定義一個(gè)函數(shù),這個(gè)函數(shù)會(huì)將收到的配置對(duì)象參數(shù)進(jìn)行處理,然后再傳給 Page 。
// wxPage.js
import http from '../utils/http'
const wxPage = function(config) {
config.http = http
return Page(config)
}
export default wxPage
復(fù)制代碼
注冊頁面的時(shí)候改用這個(gè) wxPage :
import Page from './wxPage'
Page({
data: {
text: "This is page data."
},
onLoad: function(options) {
console.log(this.http) // 打印 http 模塊變量
this.http.get(api).then(callback) // 直接調(diào)用 http 的方法
},
})
復(fù)制代碼
直接修改 Page 函數(shù)為了增強(qiáng)頁面對(duì)象,每個(gè)需要的頁面都得引入 wxPage 是一件不太省心的事;更多時(shí)候我們是在維護(hù)一個(gè)老項(xiàng)目,需要擴(kuò)展每個(gè)原有的頁面對(duì)象,這時(shí)可以直接修改 Page :
const originalPage = Page //保存原來的Page
Page = function(config) { // 覆蓋Page變量
config.http = http
return originalPage(config)
}
復(fù)制代碼
一般來說,修改 Page 的時(shí)機(jī)是在 App onLoad 的時(shí)候。這樣原有的頁面不用修改,直接就能通過 this.http 拿到 http 。 通過擴(kuò)展 Page 頁面對(duì)象實(shí)現(xiàn)常見需求1. 給生命周期方法增加通用邏輯有時(shí)我們希望在頁面注冊的 onLoad 階段執(zhí)行一些通用的邏輯,例如埋點(diǎn),打 log 等,這時(shí)可以改寫配置對(duì)象中的 onLoad 方法:
const originalPage = Page
Page = function(config) {
const { onLoad } = config
config.onLoad = function(onLoadOptions) {
// 打 log、埋點(diǎn)……
console.log('每個(gè)頁面都會(huì)打出這個(gè)log')
if (typeof onLoad === 'function') {
onLoad.call(this, onLoadOptions)
}
}
return originalPage(config)
}
復(fù)制代碼
2. 獲取上一頁頁面對(duì)象小程序中的頁面跳轉(zhuǎn)會(huì)形成一個(gè)頁面棧,棧中存放著每個(gè)頁面對(duì)象,可以通過getCurrentPages 方法獲得這個(gè)頁面棧??梢栽陧撁?nbsp;onLoad 的時(shí)候獲取這個(gè)頁面棧,然后取出倒數(shù)第二個(gè)對(duì)象,就是當(dāng)前頁上一頁的頁面對(duì)象:
// 接上...
const { onLoad } = config
config.onLoad = function(onLoadOptions) {
const pages = getCurrentPages()
this.__previousPage = pages[pages.length - 2] // 將上一頁的頁面對(duì)象賦為this.__previousPage
if (typeof onLoad === 'function') {
onLoad.call(this, onLoadOptions)
}
}
return originalPage(config)
復(fù)制代碼
這樣在頁面對(duì)象中可通過引用 this.__previousPage 獲取上一頁頁面對(duì)象的data及所有方法,這樣在一些只需要兩個(gè)頁面互動(dòng)的情景下,當(dāng)前頁直接調(diào)用上一個(gè)頁面對(duì)象的方法(相當(dāng)于回調(diào))后再返回,比通過全局狀態(tài)管理上一頁的數(shù)據(jù)要方便。 3. 跳轉(zhuǎn)頁面并傳遞數(shù)據(jù)到下一頁這個(gè)不多說了,直接看代碼吧:
// 接上
config.navigateTo = function(url, params) { // 實(shí)現(xiàn)一個(gè)navigateTo方法,參數(shù)包括跳轉(zhuǎn)url和要傳遞的參數(shù)
this.__params = params
wx.navigateTo({ url })
}
config.onLoad = function(onLoadOptions) {
const pages = getCurrentPages()
this.__previousPage = pages[pages.length - 2] // 將上一頁的頁面對(duì)象賦為this.__previousPage
if (this.__previousPage) {
onLoadOptions.params = this.__previousPage.__params // 獲取上一頁面的__params賦給onLoad函數(shù)的options
delete this.__previousPage.__params
}
if (typeof onLoad === 'function') {
onLoad.call(this, onLoadOptions)
}
}
// A 頁面跳轉(zhuǎn) B 頁面
this.navigateTo('urlToB', { foo: 'bar' })
// B 頁面的 onLoad
Page({
onLoad(options) {
console.log(options.params) // { foo: 'bar' }
}
})
復(fù)制代碼
就寫到這里吧,在使用原生方案開發(fā)的時(shí)候,這些技巧還是挺實(shí)用的。以后再寫寫怎樣構(gòu)建小程序,使小程序支持文件預(yù)編譯、require npm 包等。 |