vue里如何主动销毁keep-alive缓存的组件

问题产生的背景

我们一个后台,在切换一些标签页的时候,是使用的 keep-alive 缓存的标签页,也使用了 include 属性来决定哪个页面进行缓存,而标签页的切换实际上是路由的切换,也就是说打开一个新标签页的时候,url 会跟着变化,老的标签页如果在 keep-aliveinclude 范围内那就会缓存下来。

然后客服人员就反馈页面开的久了就会崩溃,因为他们基础上不会刷新页面(工作需要),又总有切换标签的习惯,最后导致内存越来越大最后崩溃。

依赖环境

这个项目是基于一个开源 vue 后台框架:https://github.com/PanJiaChen/vue-element-admin,然后代码一直由几个后端开发维护的!所以后端没找出问题在哪,然后就我来接手这个问题了。
写文章时,标签里竟然没有 vue 这一项,差评!

定位问题

先梳理下业务逻辑:从业务场景来说,我们在标签页之间切换时,如果刚进入的这个标签页已被缓存了,那被缓存的标签页就直接拿出来展示就行,而关闭这个标签页的时候就应该销毁对应的组件。

花了点时间查看了一下代码,发现问题在于关闭标签页的时候,虽然这个页面没在 keep-aliveinclude 里了,但是组件也没有被销毁掉,还是在缓存状态,我们可以通过 Vue Devtools 插件看到关闭后的标签页对应的组件一直还存在着:

当然,在这块 keep-alive 本身的逻辑我觉得是没问题的,主要是我们项目比较复杂,缓存的组件太多了而且会一直增加,所以最终导致崩溃。

解决问题

既然问题已经定位了,那就好解决问题了,只需要在关闭标签页的时候把对应的组件也销毁掉就好了。

经过网上一翻查找,发现销毁一个组件可以使用: this.$destroy(‘组件名') 来销毁。

先说下大概思路:keep-aliveinclude 里存的其实是一个 vuex 中的一个数据源(数据源保存的是路由名称),当关闭标签页时,这个数据源中的一项会被移除。这之前,我们在组件里监听到这个数据源的变化,如果此组件对应的路由(这个路由应在 mounted 的时候保存下来)已经不在数据源中了,那就应该销毁此组件。

代码大概如下:

const mixin = {
 data() {
  return {
   routePath: ''
  }
 },
 mounted() {
  this.routePath = this.$route.path
 },
 computed: {
  visitedViews() {
   return this.$store.state.tagsView.visitedViews
  }
 },
 watch: {
  visitedViews(value) {
   if(value 里没有了 routePath 这一项)
    this.$destroy(this.$options.name)
   }
  }
 }
}

export default mixin

这一段代码单独拎出来了,然后在需要缓存的组件里使用 mixins 混入到组件对象中,这样组件中要添加的代码量就比较少了。

更改后经过测试,关闭标签页后对应的组件就会被销毁掉,使用 Vue Devtools 能看的很清楚。

更多思考

在我们后台操作这么频繁的业务场景下,使用 keep-alive 其实并不是一个好的选择。

在我们修复这个问题后,我们通过控制台里的 Memory 查看页面内存的变化时,发现组件即便被销毁,也要经过一段时间才能回收完,当我们在这一段时间一直创建/打开新的标签页时,内存还是会在短时间内高涨。而且有时候,内存在经过一段时间后也并没有回收掉。

keep-alive 本质上是把整个 dom 节点及对应的事件等都缓存下来了,当这样的组件很多的时候,自然会占用很多内存。而如果我们只缓存这个组件中的数据,在需要这个组件再次显示的时候再临时渲染那肯定要节省很多内存的,毕竟数据占的空间其实很小的,而渲染组件要花的时间也不会很长(只要组件不是特别特别复杂)。

所以,下一阶段的优化工作就是把 keep-alive 去掉,然后使用 vuex 来缓存组件中的数据,当需要重新显示数据时再把数据取出来并重新渲染。当然,这是一个比较大的工程!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • vue服务端渲染页面缓存和组件缓存的实例详解

    vue缓存分为页面缓存.组建缓存.接口缓存,这里我主要说到了页面缓存和组建缓存 页面缓存: 在server.js中设置 const LRU = require('lru-cache') const microCache = LRU({ max: 100, // 最大缓存的数目 maxAge: 1000 // 重要提示:条目在 1 秒后过期. }) const isCacheable = req => { //判断是否需要页面缓存 if (req.url && req.url ===

  • vue 指定组件缓存实例详解

    keep-alive 简介 keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,或避免重新渲染. 用法也很简单: <keep-alive> <component> <!-- 该组件将被缓存! --> </component> </keep-alive> props include - 字符串或正则表达,只有匹配的组件会被缓存 exclude - 字符串或正则表达式,任何匹配的组件都不会被缓存 // 组件 a export

  • vue 使某个组件不被 keep-alive 缓存的方法

    提出问题 最近在做项目发现一个问题,当我使用了 keep-alive 标签后,进入了某个路由进行一系列操作,再点击浏览器后退,再次进入刚才的路由,页面被操作的数据没有初始化! 分析问题 这是因为 keep-alive 将路由页面缓存,所以该路由没有完成整个生命周期,没有 destroyed,因此重新进入也没有触发其他生命周期钩子,如 created 等. 解决问题 (1). 查看官方文档 当组件在 keep-alive 内被切换,它的 activated 和 deactivated 这两个生命周

  • 详解Vue中组件的缓存

    之前在<Vue一个案例引发的动态组件与全局事件绑定总结>这篇文章中简单提到过组件的缓存.当时只是简单的提供了一个解决问题的思路,并没有说到多少组件缓存的东西,今天我们就来详细说说组件的缓存. 组件化开发模式下,我们会把整个项目拆分成很多组件,然后按照合理的方式组织起来. 自然就存在组件之间的切换问题,Vue 中有个「动态组件」的概念,它能够让我们更好的实现组件的切换. 在实际的项目开发中,产品是不可能放过我们的,需求总是在不停的变化,如果你碰到那些不改需求的产品就嫁了吧,太难得了. 最近项目中

  • vue里如何主动销毁keep-alive缓存的组件

    问题产生的背景 我们一个后台,在切换一些标签页的时候,是使用的 keep-alive 缓存的标签页,也使用了 include 属性来决定哪个页面进行缓存,而标签页的切换实际上是路由的切换,也就是说打开一个新标签页的时候,url 会跟着变化,老的标签页如果在 keep-alive 的 include 范围内那就会缓存下来. 然后客服人员就反馈页面开的久了就会崩溃,因为他们基础上不会刷新页面(工作需要),又总有切换标签的习惯,最后导致内存越来越大最后崩溃. 依赖环境 这个项目是基于一个开源 vue

  • 关于vue里页面的缓存详解

    keep-alive是vue内置的一个组件,可以使被它包含的组件处于保留状态,或避免被重新渲染. 用法: 运行结果描述: input输入框内,路由切换输入框内部的内容不会发生改变. 在keep-alive标签内部添加 include:字符串或正则表达式.只有匹配的组件会被缓存 exclude: 字符串或正则表达式.任何匹配的组件都不会被缓存. 结合router缓存部分页面: 比较实用的例子: 思路:通过beforeRouterLeave这个钩子来对路由里面的keepAlive进行赋值.从而动态的

  • vue项目优化之通过keep-alive数据缓存的方法

    <keep-alive>是Vue的内置组件,能在组件切换过程中将状态保留在内存中,防止重复渲染DOM. <keep-alive> 包裹动态组件时,会缓存不活动的组件实例,而不是销毁它们.和 <transition> 相似,<keep-alive> 是一个抽象组件:它自身不会渲染一个 DOM 元素,也不会出现在父组件链中. prop: include: 字符串或正则表达式.只有匹配的组件会被缓存. exclude: 字符串或正则表达式.任何匹配的组件都不会被缓

  • 在vue里使用codemirror遇到的问题

    前提小结: 第一次用codemirror,而且是在vue里面使用,看了官方文档,一大串都是英文,翻译后大概了解了这个插件,然后在项目中使用时出现过好几个问题: 1.新版的codemirror在lib目录下没有codemirror.js文件,旧版的有,所以网上的很多文章都是直接这样引: <scriptsrc="lib/codemirror.js"></script> <linkrel="stylesheet"href="../l

  • 解决Vue keep-alive 调用 $destory() 页面不再被缓存的情况

    需求: 项目中需要开发一个导航栏,类似浏览器的导航,没有关闭的时候页面缓存,关掉之后,页面随之销毁.(如图) 项目是使用Vue + Vue-Router + Vuex 刚开始使用的方法是:关闭导航标签,直接调用对应的页面的$destory()方法,OK,可以实现关闭页面(下次再打开该页面,将初始化)的功能,但是遇到个问题: 该页面将不再被缓存,也就是说切换导航tab时,页面将不断的被初始化!!! 查了一下文档,找了度娘,没发现解决方法,又去请教G哥,这才发现原来Vue keep-alive真的有

  • 解决vue里碰到 $refs 的问题的方法

    本篇文章介绍了vue里碰到 $refs 的问题,分享给大家,希望能帮助大家解决问题 记录困惑自己一个简单的问题...(瞬间感觉官方文档的强大) 在自己做的一个项目中,遇到一个列表页,根据id能进入详情页(动态匹配路由),详情页是单独的一个组件,在这个详情的组件里,我想获取内容给你区域的高度,以此来判断对底部按钮显示的位置,但是在ref的时候,就是获取不到该标签,在mounted钩子函数里打印 this.$refs,也能看到这个值,但就就是点不出来(this.$refs这个对象里这个值,但是就是获

  • 对vue里函数的调用顺序介绍

    method用来定义方法的,比如你@click="test",methods就定义test这个方法 created和ready都是 vue 组件的生命周期 created 类型: Function 详细: 在实例创建之后同步调用.此时实例已经结束解析选项,这意味着已建立:数据绑定,计算属性,方法,watcher/事件回调.但是还没有开始 DOM 编译,$el 还不存在. ready 类型: Function 详细: 在编译结束和 el第一次插入文档之后调用,如在第一次attached钩

  • vue里input根据value改变背景色的实例

    1.首先定义两个不同的 .null-input .el-input__inner { background-color: rgba(255, 255, 255, 0.8); color: #525661; font-size: 16px; } .no-null-input .el-input__inner { background-color: rgba(255, 255, 255, 1); color: #524F52; font-size: 16px; } 2.根据:class 控制inpu

  • vue里的data要用return返回的原因浅析

    官网的示例 var vm = new Vue({ el: '#example', data: { message: 'Hello' } }); 项目中的写法 data() { return { message: 'Hello' } } 为什么要把data变成函数并return属性呢? 组件是一个可复用的实例,当你引用一个组件的时候,组件里的data是一个普通的对象,所有用到这个组件的都引用的同一个data,就会造成数据污染. 将data封装成函数后,在实例化组件的时候,我们只是调用了data函数

  • Vue中对iframe实现keep alive无刷新的方法

    前言 最近一个需求,需要在 Vue 项目中加入 含有iframe 的页面,同时在路由切换的过程中,要求iframe的内容 不会被刷新 .一开始使用了Vue自带的keep- alive发现没有用,于是自己研究了一下解决方案...... Vue的keep-alive原理 要实现对保持iframe页的状态.我们先搞清楚为什么Vue的keep-alive不能凑效.keep-alive原理是把组件里的节点信息保留在了 VNode (在内存里),在需要渲染时候从Vnode渲染到真实DOM上.iframe页里

随机推荐