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