vue中不同路由共用同一个组件,缓存数据。不同路由第一次进入走加载,二次缓存

2023-10-30

背景:后端根据不同路由返回不同数据,使用一个组件去渲染页面

需求:一,每次新路由进入的同一个组件都要走生命周期,获取后端数据。二,第二次点击需要缓存数据,希望之前输入的数据还在。

难点说明

1,由于vue设计时,同一个组件二次进入是不会再次走生命周期,目的是为了提高渲染效率等

2,keepAlive缓存同一个组件 会出现不生效的问题

解决:

关于一:解决方法网上但部分是根据路由在添加一个时间作为key来解决。

但我今天的解决办法是一二一起解决。

首先,先解决为什么keepAlive不能缓存同一个组件?

这里查看源码:keep-Alive.js 的render函数。由于key是相同的,所以每次缓存都会返回相同的vnode节点

  render () {
    const slot = this.$slots.default
    const vnode: VNode = getFirstComponentChild(slot)
    const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
    if (componentOptions) {
      const name: ?string = getComponentName(componentOptions)
      const { include, exclude } = this
      if (
        // 不再白名单里面的
        (include && (!name || !matches(include, name))) ||
        // 在黑名单里面的
        (exclude && name && matches(exclude, name))
      ) {
        return vnode
      }

      const { cache, keys } = this
      // 这里的key 就是为什么不能缓存同一个组件的关键
      const key: ?string = vnode.key == null ? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
        : vnode.key
      if (cache[key]) {
        vnode.componentInstance = cache[key].componentInstance
        remove(keys, key)
        keys.push(key)
      } else {
        cache[key] = vnode
        keys.push(key)
        // prune oldest entry
        if (this.max && keys.length > parseInt(this.max)) {
          pruneCacheEntry(cache, keys[0], keys, this._vnode)
        }
      }

      vnode.data.keepAlive = true
    }
    return vnode || (slot && slot[0])
  }

所以这里我们需要重新构建一个新的keep-alive ,目的是能够随心所欲的使用key去缓存不同的vnode节点。

目录结构:

外层代码:

<style scoped>
.page-view {
  height: 100%;
}
</style>
<script type="text/jsx">
import BlKeepAlive from "./BlKeepAlive";
export default {
  name: "PageView",
  functional: true,
  props: {
    include: {
      type: Array,
      default: () => [],
    },
  },
  render(h, context) {
    const { include } = context.props;
    return (
      <BlKeepAlive include={include}>
        <transition mode="out-in">
          <router-view />
        </transition>
      </BlKeepAlive>
    );
  },
};
</script>

 BlKeepAlive代码

<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) {
 // 这里可以控制自己想要的key
 return route.path
}
export default {
  name: "bl-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>

然后:解决从新加载页面和起到缓存作用,还有一个关键点,需要在路由 beforeEach中做一个中转跳转。就是对于相同组件,每次进入都需要先跳转到中转页面,在从中转页面跳回目标页面。

这样不经可以让同一个组件走生命周期,在缓存时也会正确返回缓存页面。

路由:

import Vue from "vue";
import VueRouter from "vue-router";
const Home = () => import("../views/Home.vue");
const Redirect = () => import("../views/Redirect");

Vue.use(VueRouter);

const routes = [
  {
    path: "/home/:id",
    name: "Home",
    meta: {
      title: "共用组件",
    },
    component: Home,
  },
  {
    path: "/redirect",
    name: "Redirect",
    component: Redirect,
    children: [
      {
        path: '*',
        component: Redirect,
        meta: {
          cantCheck: true
        }
      }
    ]
  },
];

const router = new VueRouter({
  mode: "history",
  base: process.env.BASE_URL,
  routes,
});

/**
 * @description: 在进入路由前验证各种状态
 * @param {type}
 * @return:
 */
router.beforeEach((to, from, next) => {
  console.log(to.meta,to.meta.title)
  if (to.meta.title !== undefined && to.meta.title === from.meta.title) {
    next(`/redirect${to.path}`);
  } else {
    next();
  }
});

export default router;

路由beforeEach,先判断是否是同一个组件,如果是先回重定向到redirect页面

重定向Redirect代码:

<script>
  function replaceAll(str, substr, replacement) {
    if (str == null) return str
    return str.replace(new RegExp(substr, 'gm'), replacement)
  }
  export default {
    mounted() {
      const {path} = this.$route
      this.$router.replace(`${replaceAll(path, '/redirect', '')}`)
    },
    render: h => h()
  }
</script>

至此:核心代码都写完了,重写keepAlive和增加了一个重定向。这样就可以解决同一个组件,根据不同的路由,第一次进入刷新,第二次进入缓存

后面贴出调用代码:这里是demo所以我直接在app里面写了

<template>
  <div id="app">
    <div id="nav">
      <router-link to="/home/1">
        <button @click="goUrl('/home/1')">Home</button>
      </router-link>
      <router-link to="/home/2">
        <button @click="goUrl('/home/2')">Home2</button></router-link
      >
    </div>
    
    <bl-page-view :include="myInclude">
      <router-view />
    </bl-page-view>
  </div>
</template>
<script>
import BIPaveView from "./components/BIPaveView/index.vue";

export default {
  name: "App",
  components: {
    "bl-page-view": BIPaveView,
  },
  data() {
    return {
      myInclude: [],
    };
  },
  methods: {
    goUrl(url) {
      let arr=[].concat(this.myInclude)
      if (!arr.includes(url)) {
        arr.push(url);
      }
       this.myInclude=arr
    },
  },
};
</script>

<style lang="less">
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
}
</style>

公共组件

<template>
  <div class="home">
    <input
      v-for="(item, index) in inputArr"
      :key="index"
      type="text"
      v-model="item.num"
    />
  </div>
</template>

<script>
export default {
  name: "Home",
  data() {
    return {
      inputArr: [],
      pageCode: 1,
    };
  },

  created() {
    console.log("我走生命周期了", this.$route);
    this.pageCode = this.$route.params.id * 1;
    this.clearData();
    this.getNewData();
  },
  methods: {
    clearData() {
      this.inputArr = [];
    },
    getNewData() {
      let ss = {
        1: [{ num: "" }],
        2: [{ num: "" }, { num: "" }],
      };
      this.inputArr = ss[this.pageCode];
    },
  },
};
</script>

实现效果:

视频暂时未审核:https://live.csdn.net/v/191810

不知这个地址你们可以访问不。反正就是演示了第一次加载后,输入数据再次进入会缓存

 

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

vue中不同路由共用同一个组件,缓存数据。不同路由第一次进入走加载,二次缓存 的相关文章

随机推荐

  • 微信小程序 实现最简单的组件拖拽

    背景 最近在自主学习微信小程序的开发 对于零基础入门 没有学习过前端 的我 查阅了许多微信小程序拖拽的实现 大部分要么实现起来太复杂了 要么封装组件太复杂了 附带了拖拽之后排序等功能 因此写下这篇个人觉得最好理解的 微信小程序元素拖拽的实现
  • Eclipse软件需要JAVA JDK版本对应关系

    每一个版本的Eclipse开发平台软件需要的JAVA JDK的版本不同 需要根据IBM公司公布的对应关系配对 才能开发Android项目 下面是IBM公司公布的对应关系 链接为 http wiki eclipse org Eclipse I
  • c# 面试题

    简述 private protected public internal 修饰符的访问权限 答 Private 拍非得 私有成员 在类的内部才可以访问 protected 普泰忒 保护成员 该类内部和继承类中可以访问 Public 怕本科
  • 商标注册查询入口官网502打不开服务器网络不通?怎么解决?

    商标注册查询入口官网为http wcjs sbj cnipa gov cn txnT01 do打开后发现提示502错误 当你打开商标注册查询入口官网发现502错误 502错误是指服务器端网络不通 这是商标网服务器的问题 作为商标注册查询用户
  • Z检验

    Z检验也叫做正态分布的标准正态分布变量检验 它通常用于大样本 样本容量大于30 且总体标准差已知的情况下 用于比较样本均值与总体均值之间的差异是否显著 Z检验的基本思想都是计算样本均值与参考值或另一个样本均值之间的差异 然后将其标准化为标准
  • 【汇编的简单操作】

    汇编的基本操作 汇编的学习方法就是多看 多写 注意细节 我用的汇编工具是EditPlus 2 文章目录 汇编的基本操作 一 汇编模板 二 寄存器 常用指令 快速排序 编程实现输出 1 2 n 个数全排列 迷宫问题 总结 一 汇编模板 总体
  • GPIO操作流程

    说明 有时候需要通过adb将gpio电平拉高拉低 具体实现如下 实现 创建gpio 并且拉高gpio90 1 adb shell 2 cd sys class gpio 3 echo 90 gt export 4 echo out gt g
  • 《HTML 5与CSS 3核心技法》读书笔记

    目录 前言 第1章 写在前面 第2章 HTML 语法基础 第3章 布局类元素 房子的楼板 柱子和大梁 第4章 功能类元素 房子的门 窗 水管和电气 第5章 CSS基础 第6章 选择器 确定样式的作用范围 选择器类型 选择器的组合使用 第7章
  • redis安全防护

    Redis没有实现访问控制这个功能 但是它提供了一个轻量级的认证方式 可以编辑redis conf配置来启用认证 Redis 未授权访问漏洞 Redis设置认证密码加固建议 防止这个漏洞需要修复以下三处问题 第一 修改redis绑定的IP
  • 代理ARP(Proxy Arp)

    ARP代理 代理ARP Proxy arp 的原理就是当出现跨网段的ARP请求时 路由器将自己的MAC返回给发送ARP广播请求发送者 实现MAC地址代理 善意的欺骗 最终使得主机能够通信 代理ARP的应用场景 场景1 电脑可以随意设置网关地
  • FPGA内部结构、内容及面试题

    1 FPGA内部结构及内容 2 FPGA面试题 xx
  • 这可能是目前最好的vue代码生成工具

    1 项目介绍 Esview是一款拖拽组件生成页面的工具 并且可以生成vue代码 包含拖拽生成页面 页面管理 组件管理等功能 前端采用vue和iview 生成的代码必须安装vue和iview才能使用 后台采用java springboot 作
  • python基础4——类、异常处理、常用模块

    文章目录 一 类 二 python异常处理 三 自定义模块 3 1 保留模块测试代码 3 2 添加模块使用说明 四 内置模块 4 1 os标准库 4 2 os path类 4 3 sys库 4 4 platform库 4 5 glob库 4
  • C ~ 输入 & 输出

    提到输入时 意味着要向程序填充一些数据 输入可以是以文件的形式或从命令行中进行 C 语言提供了一系列内置的函数来读取给定的输入 并根据需要填充到程序中 提到输出时 这意味着要在屏幕上 打印机上或任意文件中显示一些数据 C 语言提供了一系列内
  • qt的gui主线程while死循环避免界面卡掉

    unsigned long lTick GetTickCount while m ComResult GetTickCount lTick lt 300 Sleep 50 QCoreApplication processEvents QEv
  • JS给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置

    给定一个排序数组和一个目标值 在数组中找到目标值 并返回其索引 如果目标值不存在于数组中 返回它将会被按顺序插入的位置 请必须使用时间复杂度为 O log n 的算法 示例 1 输入 nums 1 3 5 6 target 5 输出 2 示
  • 在React中解析渲染markdown文件

    解决办法 安装marked对md文件进行解析 npm install marked save 基本使用 import marked from marked const rendererMD new marked Renderer marke
  • Windows下使用XShell上传、下载文件到linux服务器

    安装lrzsz sudo apt install lrzsz 输入下面的命令 选择本地文件上传到服务器 rz 可以进行文件上传 使用sz命令时注意需要加一个参数 下载哪一个文件到本地 sz test md
  • 如何花30多块打造Home Assistant智能家居盒子

    环境 HW悦盒ec6108v9c Home Assistant 2023 3 6 问题描述 如何花30多块打造Home Assistant智能家居盒子 解决方案 1 XY寻找HW悦盒ec6108v9c 最后35成交 2 拿到手后刷机 把系统
  • vue中不同路由共用同一个组件,缓存数据。不同路由第一次进入走加载,二次缓存

    背景 后端根据不同路由返回不同数据 使用一个组件去渲染页面 需求 一 每次新路由进入的同一个组件都要走生命周期 获取后端数据 二 第二次点击需要缓存数据 希望之前输入的数据还在 难点说明 1 由于vue设计时 同一个组件二次进入是不会再次走