小程序嵌套H5的方式和技巧(二)

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

 

posted @ 2021-11-23 17:46  王阿灿  阅读(1664)  评论(0编辑  收藏  举报