• 使用自定义的keep-alive组件,将公共页面缓存多份,都有自己的生命周期


    背景:将tab页面缓存,例如A页面输入123,通过tab标签跳转到B页面,再点击A标签,跳转回A页面,这时需要保留输入的123 。本来,直接使用keep-alive就行了,但是这几个路由绑定的是同一个页面。。。。。。

    • 多个路由绑定同一个页面路由配置
     { path: '/A', name: 'A', component: CommonPage },
      { path: '/B', name: 'B', component: CommonPage },
      { path: '/C', name: 'C',component: CommonPage },
      { path: '/D', name: 'D',component: CommonPage },
    
    • 1
    • 2
    • 3
    • 4
    • 为什么不能直接使用keep-alive(个人理解)
      因为keep-alive是默认根据.vue文件的export default { name: 'StaStationPage',name属性来进行页面缓存的,但是多个路由指向同一个页面,那对于keep-alive来说,就只有一个对象,所以只会缓存一份。

    解决方案

    • 不使用.vue文件的name属性,改用路由地址path,或路由名称name,这种比较唯一性的值作为keep-alive缓存条件,以下是自定义的keep-alive组件代码myKeepAlive.vue
    <script>
      function isEmpty(...str) {
        return str.some((i) => i === undefined || i === null || i === "");
      }
      function getFirstComponentChild(children) {
        if (Array.isArray(children)) {
          return children.find(
            (c) =>
              !isEmpty(c) &&
              (!isEmpty(c.componentOptions) || (c.isComment && c.asyncFactory))
          );
        }
      }
      function removeCache(cache, key) {
        const cached = cache[key];
        cached && cached.componentInstance && cached.componentInstance.$destroy();
        delete cache[key];
      }
      function getRouterViewCacheKey(route) {
        // 建议使用route配置的那些属性作为key,例如path、name等
        return route.path
      }
      export default {
        name: "my-keep-alive",
        abstract: true,
        props: {include: Array},
        created() {
          this.cache = Object.create(null);
        },
        beforeDestroy() {
          for (const key of Object.keys(this.cache)) {
            removeCache(this.cache, key);
          }
        },
        render() {
          const slot = this.$slots.default;
          const vnode = getFirstComponentChild(slot);
          let componentOptions = vnode && vnode.componentOptions;
          if (componentOptions) {
            const child =
              componentOptions.tag === "transition"
                ? componentOptions.children[0]
                : vnode;
            componentOptions = child && child.componentOptions;
            if (componentOptions) {
              const key = getRouterViewCacheKey(this.$route)
              const { cache,include } = this;
    
              if (include && !include.includes(key)) {
                console.log('不含有缓存返回',include,key)
                return vnode
              }
    
              if (cache[key]) {
                child.componentInstance = cache[key].componentInstance;
              } else {
                cache[key] = child;
              }
              child.data.keepAlive = true;
            }
          }
    
          return vnode || (slot && slot[0]);
        },
      };
    </script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 添加中转页面,使得第一次进入该路由时,触发created,重新进入生命周期,实现第一次加载,第二次缓存的效果
      路由配置如下
    {
        path: "/redirect",
        name: "Redirect",
        component: Redirect,
        children: [
          {
            path: '*',
            component: Redirect,
            meta: {
              cantCheck: true
            }
          }
        ]
      },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Redirect.vue页面代码如下:

    <script>
      function replaceAll(str, substr, replacement) {
        if (str == null) return str
        return str.replace(new RegExp(substr, 'gm'), replacement)
      }
      export default {
        mounted() {
          console.info('this.$route', this.$route)
          const {fullPath} = this.$route
          this.$router.replace(`${replaceAll(fullPath, '/redirect', '')}`)
        },
        render: h => h()
      }
    </script>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    路由守卫permission.js,在路由跳转前,跳转到中转页面,再由中转页面跳到目标页面

    	// 通过title,判断是否使用通过一个页面,并决定是否跳转到中转页
      if (to.meta.title !== undefined && to.meta.title === from.meta.title) {
        next(`/redirect${to.fullPath}`);
      } else {
        next();
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    原有路由配置新增meta参数,修改为如下配置

      { path: '/A', name: 'A', meta: {title: 'onePage'}, component: CommonPage },
      { path: '/B', name: 'B', meta: {title: 'onePage'}, component: CommonPage },
      { path: '/C', name: 'C', meta: {title: 'onePage'}, component: CommonPage },
      { path: '/D', name: 'D', meta: {title: 'onePage'}, component: CommonPage },
    
    • 1
    • 2
    • 3
    • 4

    至此,学习笔记记录

  • 相关阅读:
    [其他] ubuntu 22 上编译 ffmpeg
    Unity——导航系统补充说明
    mysql5.7.35安装配置教程【超级详细安装教程】
    2023年【危险化学品生产单位安全生产管理人员】复审考试及危险化学品生产单位安全生产管理人员考试试题
    爬虫反爬:JS逆向实战练习1
    (十一)Python模块和包
    【目标跟踪】|单目标跟踪指标
    微信小程序 wx:if使用
    机器学习-K近邻算法
    深入学习JVM底层(一):Java内存区域
  • 原文地址:https://blog.csdn.net/BluerCat/article/details/128001525