文章接上文,小程式巢狀H5的方式和技巧(一)
四、重新整理wev-view巢狀的H5頁面
1)我們為什麼要重新整理wev-view巢狀的H5頁面?
很多的業務場景都需要開發者每次開啟頁面都更新一下頁面的資料。原生小程式更新頁面的資料就比較簡單了,通常在onshow裡處理就可以了,每次進入onshow生命週期直接呼叫介面來重新整理資料就可以了,而小程式用web-view元件巢狀H5來重新整理頁面資料可就沒那麼簡單了。下面我來用實際場景來舉例。
我們用三個頁面:首頁,頁面A和頁面B,三個頁面都有不同的殼,巢狀的不同的H5頁面。
首頁:頁面元素包含banner圖,點選banner圖會進入活動說明頁A
活動說明頁A:頁面的元素包括參與活動需要滿足的條件,獲得獎勵的人數限制,獲得獎勵的參與人員列表,去參加活動的按鈕
活動詳情頁B:頁面的元素包括活動的主頁面,返回上一頁的按鈕
2)常規方法有回退兩次的問題
使用者從頁面A進入到頁面B,使用者在B參與活動後返回上一頁到頁面A,此時需求希望頁面重新整理。通常我們會這麼寫:
wxml檔案
// 首頁 Page({ data: { }, onReady(){ setTimeout(()=> { // 模擬點選頁面跳轉到活動頁面A wx.navigateTo({ url: '/pages/A/A' }) }, 5000) } }) // 頁面A Page({ /** * 頁面的初始資料 */ data: { src: "" }, /** * 生命週期函式--監聽頁面初次渲染完成 */ onReady: function () { setTimeout(()=>{ // 模擬點選跳轉到頁面B wx.navigateTo({ url: '/pages/B/B' }) }, 5000) }, /** * 生命週期函式--監聽頁面顯示 */ onShow: function () { let t = +new Date(); this.setData({ src: `https://www.baidu.com?t=${t}` }) } }) // 頁面B程式碼 Page({ /** * 頁面的初始資料 */ data: { src: "" }, /** * 生命週期函式--監聽頁面載入 */ onLoad: function (options) { this.setData({ src: `https://developers.weixin.qq.com/community/homepage` }) } })
經過上面的描述流程後:首頁→活動說明頁A→活動詳情頁B→返回上一頁,回到活動說明頁A;此時我們點選左上角的返回按鈕,我們預期的效果是回到首頁,但是實際的效果是web-view巢狀的H5頁面重新整理了一下,並沒有回退至首頁。
3)嘗試修改問題,反而引發其他更嚴重問題
嘗試解決該問題,修改頁面A的程式碼為
<!--頁面A的wxml--> <view wx:if="{{src}}"> <web-view src="{{src}}"></web-view> </view> // 頁面A Page({ /** * 頁面的初始資料 */ data: { src: "" }, /** * 生命週期函式--監聽頁面初次渲染完成 */ onReady: function () { setTimeout(()=>{ // 模擬點選跳轉到頁面B wx.navigateTo({ url: '/pages/B/B' }) }, 5000) }, /** * 生命週期函式--監聽頁面顯示 */ onShow: function () { let t = +new Date(); this.setData({ src: `` }) this.setData({ src: `https://www.baidu.com?t=${t}` }) } })
修改程式碼後,再經過流程後:首頁→活動說明頁A→活動詳情頁B→返回上一頁,回到活動說明頁A;發現頁面A空白且控制檯報錯:[渲染層錯誤] 一個頁面只能插入一個 '<web-view />'
4)功夫不負有心人,終於找到完美的解決方案
經過多次嘗試方案,發現在onHide裡面隱藏web-view(解除安裝we-bview),是可行的,貼上所有檔案的程式碼
<!--首頁的wxml--> <view class="container"> </view> // 首頁 Page({ data: { motto: '首頁' }, onReady(){ setTimeout(()=> { // 模擬點選頁面跳轉到活動頁面A wx.navigateTo({ url: '/pages/A/A' }) }, 5000) } }) <!--頁面A的wxml--> <view wx:if="{{src}}"> <web-view src="{{src}}"></web-view> </view> // 頁面A Page({ /** * 頁面的初始資料 */ data: { src: "" }, /** * 生命週期函式--監聽頁面初次渲染完成 */ onReady: function () { setTimeout(()=>{ // 模擬點選跳轉到頁面B wx.navigateTo({ url: '/pages/B/B' }) }, 5000) }, /** * 生命週期函式--監聽頁面顯示 */ onShow: function () { let t = +new Date(); this.setData({ src: `https://www.baidu.com?t=${t}` }) }, onHide: function () { this.setData({ src: `` }) } }) <!-- 頁面B的wxml --> <web-view src="{{src}}"></web-view> // 頁面B程式碼 Page({ /** * 頁面的初始資料 */ data: { src: "" }, /** * 生命週期函式--監聽頁面載入 */ onLoad: function (options) { // 頁面不需要重新整理 所以寫到onLoad生命週期裡 this.setData({ src: `https://m.mi.com/` }) } })
web-view的頁面重新整理場景是非常常見的,也與我們後面的章節密不可分,因此講的還是比較詳細的,希望能幫助到其他的開發者。
5)精益求精,精簡程式碼
結合我之前的文章,微信小程式如何重寫Page方法?以及重寫Page方法給開發者帶來的好處 我們可以把程式碼做的更簡潔:將Page方法重新,把onHide生命週期解除安裝web-view的程式碼提取出來,如果有很多的頁面需要web-view重新整理H5的話,這樣會大大節省我們的工作量和程式碼量。
首先我們需要先定義一下web-view的頁面變數及其含義
refreshSrc:如果頁面的data裡定義裡這個變數,且用這個變數來渲染web-view,則每次開啟頁面都需要重新整理頁面;注意:不需要重新整理的頁面不要把渲染web-view的src屬性定義成該變數名
精簡後的程式碼
app.js // app.js (function(){ // 小程式原來的Page方法 let originalPage = Page; // 我們自定義的Page方法 Page = function(config){ // todo 在這裡我們可以給配置物件進行加工 // 將配置物件繼續想下傳遞給小程式原來的Page方法 config.onHide = function(){ //如果頁面定義了這個變數 且變數有值則在onHide生命週期將該值置空 if(this.data.refreshSrc){ this.setData({ refreshSrc: '' }) } } originalPage (config); } })(); App({ onLaunch() { }, globalData: { } }) <!--首頁的wxml--> <view class="container"> </view> // 首頁 Page({ data: { motto: '首頁' }, onReady(){ setTimeout(()=> { // 模擬點選頁面跳轉到活動頁面A wx.navigateTo({ url: '/pages/A/A' }) }, 5000) } }) <!--頁面A的wxml--> <view wx:if="{{refreshSrc}}"> <web-view src="{{refreshSrc}}"></web-view> </view> // 頁面A Page({ /** * 頁面的初始資料 */ data: { refreshSrc: "" }, /** * 生命週期函式--監聽頁面初次渲染完成 */ onReady: function () { setTimeout(()=>{ // 模擬點選跳轉到頁面B wx.navigateTo({ url: '/pages/B/B' }) }, 5000) }, /** * 生命週期函式--監聽頁面顯示 */ onShow: function () { let t = +new Date(); this.setData({ refreshSrc: `https://www.baidu.com?t=${t}` }) } }) <!-- 頁面B的wxml --> <web-view src="{{src}}"></web-view> // 頁面B程式碼 Page({ /** * 頁面的初始資料 */ data: { src: "" }, /** * 生命週期函式--監聽頁面載入 */ onLoad: function (options) { // 頁面不需要重新整理 所以寫到onLoad生命週期裡 this.setData({ src: `https://m.mi.com/` }) } })
這部分還是為了小程式中有很多頁面需要重新整理web-view巢狀的H5,如果小程式中類似於頁面A的頁面不多,這部分則可以忽略