阅读 323

Vue实现前进/后退控制缓存/刷新

引子

PC端需求,下钻层级较多,且均为列表页。列表进入到新建页面,新建成功则返回上一页并刷新页面,编辑/新建页面直接点击返回则返回上一页页面的缓存状态。

方案

hack手法

this.$router.push({
  path: '/product',
  query: {
	t: +new Date()
  }
})复制代码

此方法虽然简单,但是有明显缺陷:

  1. 丑;

  2. 前进刷新,浏览器回退的上一页url上有时间戳,但是面包屑上点击跳转无时间戳只能刷新,除非维护页面的时间戳。

meta路由depth层级

// router-view页面

<template>
  <div id="app">
    <keep-alive :include="include">
      <router-view v-if="$route.meta.keepAlive" />
    </keep-alive>
    <router-view v-if="!$route.meta.keepAlive" />
  </div>
</template>

// router.js

meta: {
    keepAlive: true,
    deepth: x // 路由层级1,2,...n
}复制代码

监听$route维护include数组,下钻则添加当前页name(此name为.vue里的name)到数组里,回退则去除。

此方法缺陷为:

  1. 兼容性差,逻辑推演太复杂:同模块跨级跳转;不同下钻的模块间跳转。

  2. 路由文件需要静态配置一堆depth

Vuex

此方案适用于React框架。将表格查询的Filter信息存储起来,回退时用Filter查询列表,若回退想回到第一页,可跳转前修改Vuex的信息再跳转。

此方案缺陷:

  1. 不是真缓存,存在接口请求和重新渲染;

  2. 页面如果有多个接口请求,包含数据看板、多列表,存储变复杂;

  3. 滚动位置。

keepAlive刷新方案

  • 多页面会用到router,但不一定用到vuex,那么方案如下:

  1. EventBus;

  2. 监听$route变化;

  3. activated;

  • 刷新有两个方案:

  1. Html标签上添加v-if,改变成false再改回true;

  2. keepAlive标签上添加include、exclude。利用exclude优先于include,include初始值为router里所有meta为keepAlive的name集合(此name为.vue里的name,router配置的name规范成和.vue保持一致方便初始化),需要刷新时将刷新页面的name值push进exclude数组,渲染完再移除,逻辑比维护include数组简单很多。

第一个方案更通用,当前页刷新也可以使用,可以用在点击侧边栏刷新(当前页没变化不会出发$route变化和activated);第二个方案缺陷是无法刷新当前页,但使用了keepAlive自带方法更优雅。

<keep-alive :include="include" :exclude="exclude" v-if="keepAliveReload">
  <router-view></router-view>
</keep-alive>

data() {
  return {
    keepAliveReload: true,
    exclude: []
  }
},
created() {
  this.keepAliveReloadInit = Object.assign({}, this._data)
  if (!this.$eventBus._events['keepAliveReload']) {
    this.$eventBus.$on('keepAliveReload', () => {
      this.keepAliveReload = false
      this.$nextTick(() => {
        Object.assign(this, this.keepAliveReloadInit)
      })
    })
  }
},
watch: {
  $route: function(to, from) {
    if (to.meta.keepAlive && to.meta.reload) {
      this.exclude.push(to.name)
      this.$nextTick(() => {
        this.exclude.pop()
        Object.assign(this, this.keepAliveReloadInit)
      })
      to.meta.reload = false
      to.meta.loaded = true
    }
  }
}复制代码

刷新参数携带方案

  1. meta元信息;

  2. params;

    // 方案1

    this.$route.meta.reload = true

    this.$router.push('/pointExchange/accountDetail')

    // router守卫传递reload信息

    router.beforeEach((to, from, next) => { to.meta.reload = from.meta.reload from.meta.reload = false })

    // 方案2

    this.$router.push({ name: 'accountDetail', params: { reload: true } })

方案2有些缺陷:

  1. 潜在的与路由配置path/:reload冲突;

  2. 只能使用name跳转params参数才能设置成功。

方案1好处是不限制$router是path还是name跳转,且meta元信息冲突的可能性更低。

总结

最终方案为:

keepAlive缓存,在keepAlive标签上v-if,include/exclude实现刷新,通信为$route监听、EventBus(用来侧边栏刷新,见方案),刷新标识通过meta元信息传递实现。

此方案我认为通用性最高(无需vuex、多页面有router),逻辑简单,实现也不复杂。


作者:Mike 钟宪宇
链接:https://juejin.cn/post/7015118583353081863


文章分类
后端
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐