小程序内嵌 Vue H5:返回不刷新的正确姿势

在微信小程序嵌入的 Vue H5 页面中,实现页面返回不刷新,核心是保留页面的状态和实例,避免返回时重新执行生命周期(如created/mounted)或重新请求数据。由于小程序的 web-view 组件对 H5 的页面栈处理有特殊性,需结合Vue 的路由缓存机制浏览器会话存储小程序 web-view 的通信来实现,以下是具体方案:

一、核心原理

  1. Vue 路由缓存(优先推荐):利用 Vue Router 的keep-alive组件缓存页面组件实例,返回时直接复用,不重新渲染。
  2. 状态持久化:将页面数据存储在sessionStorage/localStorage或 Vuex(配合持久化插件),返回时读取数据恢复状态。
  3. 小程序 web-view 的页面栈控制:通过小程序与 H5 的通信,避免返回时重新加载 H5 页面。

二、方案一:Vue 路由缓存(keep-alive

这是 Vue 单页应用(SPA)中最原生的方案,适用于 H5 内部的路由跳转(如/pageA → /pageB,返回/pageA不刷新)。

1. 基本使用(缓存所有页面)

在 Vue 的根路由出口处包裹keep-alive,缓存所有被切换的路由组件:

<!-- App.vue -->
<template>
  <div id="app">
    <!-- keep-alive 缓存路由组件 -->
    <keep-alive>
      <router-view />
    </keep-alive>
  </div>
</template>

此时,路由切换(如从pageB返回pageA)时,pageA的组件实例会被保留,不会重新执行created/mounted,仅触发activated(激活)和deactivated(失活)生命周期。

2. 精准缓存(指定页面缓存)

如果只需缓存部分页面,可通过include/exclude属性控制(需给路由组件设置name):

<!-- App.vue -->
<template>
  <div id="app">
    <!-- 只缓存name为PageA、PageB的组件 -->
    <keep-alive include="PageA,PageB">
      <router-view />
    </keep-alive>
  </div>
</template>
// 路由组件(pageA.vue)
export default {
  name: 'PageA', // 必须与include中的名称一致
  // ...
}
3. 结合路由元信息(动态缓存)

通过路由的meta字段标记是否需要缓存,更灵活:

// router/index.js(Vue Router配置)
import Vue from 'vue'
import Router from 'vue-router'
import PageA from '@/pages/PageA'
import PageB from '@/pages/PageB'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/pageA',
      name: 'PageA',
      component: PageA,
      meta: { keepAlive: true } // 标记需要缓存
    },
    {
      path: '/pageB',
      name: 'PageB',
      component: PageB,
      meta: { keepAlive: false } // 不需要缓存
    }
  ]
})
<!-- App.vue -->
<template>
  <div id="app">
    <!-- 根据meta.keepAlive动态缓存 -->
    <keep-alive>
      <router-view v-if="$route.meta.keepAlive" />
    </keep-alive>
    <router-view v-if="!$route.meta.keepAlive" />
  </div>
</template>
4. 缓存中的生命周期处理

keep-alive缓存的组件,不再触发created/mounted,而是触发:

  • activated:组件被激活时触发(每次进入页面都会执行)。
  • deactivated:组件失活时触发。

示例:在activated中判断是否需要重新请求数据,created中只执行一次初始化:

// pageA.vue
export default {
  name: 'PageA',
  data() {
    return {
      list: [] // 页面数据
    }
  },
  created() {
    // 只执行一次:初始化静态数据、绑定事件等
    console.log('页面首次创建')
  },
  mounted() {
    // 只执行一次:DOM相关操作
    console.log('页面首次挂载')
  },
  activated() {
    // 每次进入页面执行:判断数据是否存在,不存在则请求
    if (!this.list.length) {
      this.fetchData() // 请求数据
    }
    console.log('页面激活')
  },
  deactivated() {
    // 离开页面执行:清理定时器、取消请求等
    console.log('页面失活')
  },
  methods: {
    async fetchData() {
      // 模拟接口请求
      const res = await new Promise(resolve => {
        setTimeout(() => resolve({ list: [1, 2, 3] }), 500)
      })
      this.list = res.list
    }
  }
}

三、方案二:状态持久化(应对页面刷新 / 小程序跳转)

如果 H5 页面跳转到小程序原生页面后再返回,或 H5 页面被刷新(如小程序 web-view 重新加载),keep-alive的缓存会失效,此时需要将数据持久化到sessionStorage/localStorage或 Vuex(配合vuex-persistedstate)。

1. 手动使用sessionStorage

在页面数据变化时存储,在页面初始化时读取:

// pageA.vue
export default {
  data() {
    return {
      list: []
    }
  },
  created() {
    // 初始化时读取sessionStorage中的数据
    const cacheData = sessionStorage.getItem('pageA_list')
    if (cacheData) {
      this.list = JSON.parse(cacheData)
    } else {
      this.fetchData() // 无缓存则请求数据
    }
  },
  methods: {
    async fetchData() {
      const res = await new Promise(resolve => {
        setTimeout(() => resolve({ list: [1, 2, 3] }), 500)
      })
      this.list = res.list
      // 存储数据到sessionStorage
      sessionStorage.setItem('pageA_list', JSON.stringify(this.list))
    },
    // 可选:离开页面时清理缓存(根据需求)
    beforeDestroy() {
      // sessionStorage.removeItem('pageA_list')
    }
  }
}
2. Vuex 持久化(推荐多页面共享数据)

使用vuex-persistedstate插件将 Vuex 的状态持久化到sessionStorage/localStorage

# 安装插件
npm install vuex-persistedstate --save
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
import createPersistedState from 'vuex-persistedstate'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    pageAData: [] // 存储pageA的数据
  },
  mutations: {
    SET_PAGEA_DATA(state, data) {
      state.pageAData = data
    }
  },
  actions: {
    fetchPageAData({ commit }) {
      // 模拟接口请求
      return new Promise(resolve => {
        setTimeout(() => {
          const data = [1, 2, 3]
          commit('SET_PAGEA_DATA', data)
          resolve(data)
        }, 500)
      })
    }
  },
  // 配置持久化:存储到sessionStorage(默认localStorage)
  plugins: [
    createPersistedState({
      storage: window.sessionStorage, // 会话存储,关闭小程序后失效
      paths: ['pageAData'] // 只持久化pageAData字段
    })
  ]
})
// pageA.vue
import { mapState, mapActions } from 'vuex'
export default {
  computed: {
    ...mapState(['pageAData'])
  },
  created() {
    if (!this.pageAData.length) {
      this.fetchPageAData()
    }
  },
  methods: {
    ...mapActions(['fetchPageAData'])
  }
}

四、方案三:小程序 web-view 与 H5 的通信(应对跨端跳转)

如果 H5 页面需要跳转到其他 H5 页面(跨域名)或小程序原生页面,返回时避免刷新,需通过小程序的web-view组件的通信能力控制。

1. H5 跳转到小程序原生页面(返回时保留 H5 状态)
  • 步骤 1:H5 中调用微信 JS-SDK 的wx.miniProgram.navigateTo跳转到小程序原生页面。
  • 步骤 2:小程序原生页面返回时,使用wx.navigateBack回到 H5 页面,此时 H5 页面的keep-alive缓存或sessionStorage数据仍存在,不会刷新。
// H5页面中(需先引入微信JS-SDK)
wx.miniProgram.navigateTo({
  url: '/pages/nativePage/nativePage' // 小程序原生页面路径
})
2. H5 跳转到另一个 H5 页面(同域名 / 跨域名)
  • 同域名:使用 Vue Router 的push/replace跳转,结合keep-alive缓存(方案一)。
  • 跨域名:通过wx.miniProgram.postMessage通知小程序,由小程序的web-view组件重新加载新的 H5 地址,返回时通过sessionStorage恢复状态(方案二)。

五、注意事项

  1. 小程序 web-view 的缓存机制:小程序的web-view组件默认会缓存 H5 页面的资源,但页面的 JS 上下文会在跳转后销毁,因此keep-alive仅适用于 H5 内部的路由跳转,跨端跳转需用持久化方案。
  2. sessionStorage 的限制sessionStorage与页面的会话关联,关闭小程序后会失效,若需长期保存数据,可使用localStorage(需注意数据清理)。
  3. 数据清理:缓存的数据需在适当时机清理(如用户退出页面、数据过期时),避免占用内存或展示旧数据。
  4. Vue3 的调整:若使用 Vue3,keep-alive的使用方式略有变化(需配合<router-view v-slot="{ Component }">),但核心原理一致。

总结

  • H5 内部路由跳转:优先使用keep-alive缓存组件,结合activated/deactivated生命周期处理数据。
  • H5 页面刷新 / 跨端跳转:使用sessionStorage/Vuex 持久化存储数据,恢复页面状态。
  • 小程序与 H5 通信:通过微信 JS-SDK 实现跨端跳转,返回时利用小程序的页面栈保留 H5 状态。

以上方案可根据实际场景组合使用,确保页面返回时不刷新且状态一致。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

canjun_wen

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值