文章接上文,小程序嵌套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的頁面不多,這部分則可以忽略