小程式巢狀H5的方式和技巧(二)

王阿燦發表於2021-11-23

文章接上文,小程式巢狀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檔案
  <web-view src="{{src}}"></web-view>

//
首頁 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的頁面不多,這部分則可以忽略

 

相關文章