Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

希望keep-alive能增加可以动态删除已缓存组件的功能 #6509

Closed
okjesse opened this issue Sep 4, 2017 · 69 comments
Closed

希望keep-alive能增加可以动态删除已缓存组件的功能 #6509

okjesse opened this issue Sep 4, 2017 · 69 comments

Comments

@okjesse
Copy link

okjesse commented Sep 4, 2017

What problem does this feature solve?

我在使用vue做单页应用时,在多个功能切换的时候,希望能达到动态创建tab进行切换的效果,和以前使用iframe一样,这些tab是keep-alive的,但如果太多keep-alive的时候,浏览器内存占用会过大。我希望能够达到可切换的tab最多例如只有十个,前面的我会用程序自动关闭对应tab,此时希望能把其缓存的组件也对应清除。

What does the proposed API look like?

例如:vm.$clearKeepAlived(routerName)

@jkzing
Copy link
Member

jkzing commented Sep 4, 2017

其实这个问题之前在forum上回答过一次,这件事可以用keep-aliveinclude或者exclude做到。

给你写个简单的例子:
https://jsfiddle.net/jingkaizhao/m5tLg7wt/2/

@posva
Copy link
Member

posva commented Sep 4, 2017

isn't this a dup of #6259 ?

@jkzing
Copy link
Member

jkzing commented Sep 5, 2017

@posva Yes, similar situation. It's about to dynamically clear keep-alive cache during runtime.

@okjesse
Copy link
Author

okjesse commented Sep 5, 2017

@jkzing 非常感谢,我上面说的场景您的方法应该可以完成,但我还有个场景,例如列表页面,如果是从tab切换过来的时候,希望是keep-alive,直接从内存拿数据,如果是修改一条数据后,程序跳转到列表页面,希望是能够后台获取新的数据,虽然我可以页面完成后再从后台获取,但感觉不够优雅,如果有上述api,我只需要在修改后把这个router的keep-alive清除,数据应该就会自动从后台获取了。不知道我表述的是否能够让您明白,总之,我希望能够优雅的把单页应用做成和以前iframe的多tab效果一样: http://www.sucaihuo.com/modals/16/1653/demo/ 以上,谢谢。

@jkzing
Copy link
Member

jkzing commented Sep 5, 2017

@okjesse 这个也是可以做到的,你需要的只是把include或者exclude提升到更上层组件;或者,如果用了vuex的话把include放到vuex store中。

总之,vue提供了基础的API来完成这件事,想方便地用起来的话需要稍微封装下。

@okjesse
Copy link
Author

okjesse commented Sep 5, 2017

@jkzing 明白,谢谢了,我现在是自己写了个keep-alive实现的,我试试 按照您的方法

@okjesse
Copy link
Author

okjesse commented Sep 5, 2017

@jkzing ,不过就算这样能够实现,我觉得最好还是得有个这个api,语义会不太一样,我所希望的是清除已经keep-alive的数据,组件本身还是alive的,而不是不停的切换是否会alive

@tomatoo1
Copy link

tomatoo1 commented Sep 5, 2017

这只是其中一个问题,我们遇到的不停开新页面,会导致内存过大,最后浏览器卡死的问题,应该和keepalive无关。如果可以,我们重现个现象给@jkzing

@tomatoo1
Copy link

tomatoo1 commented Sep 5, 2017

我们要实现的是,在跳转到页面的前一刻才决定是否用缓存的页面,还是新页面。老的api做不到的吧

@jkllx
Copy link

jkllx commented Sep 20, 2017

我目前也遇到了这个需求,再菜单列表点击连接,在tabs里面增加一个标签并缓存新开的组件;点击关闭标签我希望能删除缓存的组件;我是在组件里面deactivated钩子函数调用this.$destroy();这样能清除缓存,但是发现下次打开这个连接的时候,新的组件不会被缓存了

@okjesse
Copy link
Author

okjesse commented Sep 21, 2017

@fadexiii 现有的方法我解决了,通过动态设置includes,可以实现

@jkllx
Copy link

jkllx commented Sep 21, 2017

@okjesse 我的keep-alive 里面包含的是一个<router-view></router-view>用includes的方法不起作用

@jkllx
Copy link

jkllx commented Sep 21, 2017

@okjesse 刚刚是我没有定义conponent的name属性,定义之后可以了,多谢

@okjesse okjesse closed this as completed Sep 21, 2017
@yyx990803
Copy link
Member

FYI: implemented in 2cba6d4

@JacBian
Copy link

JacBian commented Oct 31, 2017

@fadexiii #6961 和你一样的需求,请问下你们怎么解决的呀

@jkllx
Copy link

jkllx commented Oct 31, 2017

@Jack-93 利用keep-alive的include,新打开标签时,把当前组件名加入到include数组里,关闭标签时从数组中删除关闭标签的组件名就可以了

@wanyaxing
Copy link

看到$destroy这个方法,我觉得这就是正确的用法,通过组件里不同的用户行为决定离开页面时是否缓存组件。
(比如一个留言组件,留言提交成功后这个组件应该销毁,如果没有提交,则应该保留缓存,让用户下次进来继续。)
然而,destroy之后,再次重复进入这个组件会出现奇怪的结果,组件不能再被缓存了,我觉得这是bug吧。

@realfly08
Copy link

@wanyaxing 我也遇到过你类似的问题
我用了keep-alive 缓存所有的子组件,列表页A---》详情页B---》三级页面D, 在正向前进的时候,我将打开的路由全部存在sessionStorage里面,返回的时候判断是下一个路由是否在sessionStorage里面,如果在的话,就将当前实例销毁。
这样的话,第一次没问题,能正常运行,两次或者多次以后,就会出现会B被缓存多次的情况,每次从D返回至B的时候,会生成一个新的B,而之前缓存的B还一直在内存当中,如图所示:
image

核心代码如下:
image

@wanyaxing
Copy link

@realfly08 我尝试提交了一个PR去解决这个问题,不过好像提交失败了,我没搞清楚怎么通过vue的自动代码审查-。- #7151

我之前也是准备全站缓存,然后碰到了缓存更新的逻辑大坑。
现在我放弃了全站缓存,只在关键的几个表单页开启了缓存,然后在代码里动态判断是否保留当页数据,算是临时跳过了这些问题,然而我自己还是感觉这个逻辑不够爽利。

@hujianlong
Copy link

@wanyaxing 我也遇到了类似的问题,要实现的逻辑功能,A->B->C 3个页面, 返回的时候使用缓存,再次进入的时候重新渲染,目前是每个页面都keep alive, 然后我在B页面进行判断如果是返回上一级页面(go -1)就在deactivated中销毁当前组件,调用$destroy,当按顺序再次进入到C页面,返回到B页面,可以看到又重新创建了B页面,同时缓存中还存在着一个B页面

@realfly08
Copy link

https://www.jianshu.com/p/cd1baf5b03b0
这个是我整理的

@bigggge
Copy link

bigggge commented Dec 28, 2017

@fadexiii keep-alive 配合router-view怎么用?

  <keep-alive :include="includes">
     <router-view></router-view>
  </keep-alive>

includes 写的是路由配置中的name: 'login'

const router = new Router({
  routes: [
    {
      path: '/login',
      name: 'login',
      component: Login
    }]
 })

为什么我把 includes 赋值为空字符串,依然可以缓存?我的需求就是需要手动销毁缓存的路由

@leixu2txtek
Copy link

在组件被销毁之后,缓存并没有被清空掉,我觉得问题是在这里。
项目负责人推荐使用 include 这样的属性来处理,我觉得并没有直接destroy 来的直接吧,内存还能有所改善

@wanyaxing 看了你提交的PR ,应该是有效的,或者开放一个 remove cache 的API 也行的吧

@wanyaxing
Copy link

wanyaxing commented Jul 10, 2018

@leixu2txtek 我已经放弃了那个PR,通过强行清除缓存的方法,我变相得实现了动态删除缓存组件的功能。

我目前全站使用缓存,通过拦截页面离开的路由事件来根据业务逻辑实现删除缓存的功能,以下代码片段供参考:

  • 将router-view放到keep-alive中,默认全站默认使用缓存。
    <keep-alive><router-view class="transit-view"></router-view></keep-alive>
  • 我在routes里将所有的页面进行了分层。如meta.rank代表页面层次,如1.5>2.5>3.5意味着从第一层进入第二层进入第三层页面。
routes: [
{   path: '/', redirect:'/yingshou', },
{   path: '/yingshou',                meta:{rank:1.5,isShowFooter:true},          },
{   path: '/contract_list',           meta:{rank:1.5,isShowFooter:true},          },
{   path: '/customer',                meta:{rank:1.5,isShowFooter:true},          },
{   path: '/wode',                    meta:{rank:1.5,isShowFooter:true},          },
{   path: '/yingfu',                  meta:{rank:1.5,isShowFooter:true},          },
{   path: '/yingfu/pact_list',        meta:{rank:2.5},                            },
{   path: '/yingfu/pact_detail',      meta:{rank:3.5},                            },
{   path: '/yingfu/expend_view',      meta:{rank:4.5},                            },
{   path: '/yingfu/jizhichu',         meta:{rank:5.5},                            },
{   path: '/yingfu/select_pact',      meta:{rank:6.5},                            },
{   path: '/yingfu/jiyingfu',         meta:{rank:7.5},                            },
]
  • 因为所有页面都会缓存,所以核心思路是【何时销毁缓存?】。我的设计是:同层级页面切换或进入下一层页面都会保留当前页缓存,【返回上一层页面时则销毁当前页面缓存】。
  • 所以我在main.js里,使用Vue.mixin的方法拦截了路由离开事件,并在该拦截方法中实现了销毁页面缓存的功能。核心代码如下:

Vue.mixin({
    beforeRouteLeave:function(to, from, next){
        if (from && from.meta.rank && to.meta.rank && from.meta.rank>to.meta.rank)
        {//如果返回上一层,则摧毁本层缓存。
            if (this.$vnode && this.$vnode.data.keepAlive)
            {
                if (this.$vnode.parent && this.$vnode.parent.componentInstance && this.$vnode.parent.componentInstance.cache)
                {
                    if (this.$vnode.componentOptions)
                    {
                        var key = this.$vnode.key == null
                                    ? this.$vnode.componentOptions.Ctor.cid + (this.$vnode.componentOptions.tag ? `::${this.$vnode.componentOptions.tag}` : '')
                                    : this.$vnode.key;
                        var cache = this.$vnode.parent.componentInstance.cache;
                        var keys  = this.$vnode.parent.componentInstance.keys;
                        if (cache[key])
                        {
                            if (keys.length) {
                                var index = keys.indexOf(key);
                                if (index > -1) {
                                    keys.splice(index, 1);
                                }
                            }
                            delete cache[key];
                        }
                    }
                }
            }
            this.$destroy();
        }
        next();
    },
});

总结:其实就是通过页面组件所在的上层keepAlive组件,暴力操控该对象中的cache列表。。。

简单又直接,虽然不是很优雅,然而很好用,哈哈:)

当然还是希望官方能支持API出来更好。

@leixu2txtek
Copy link

@wanyaxing 我是通过路由来控制页面的缓存

比如,我有 /executed/,以及他的子路由 /executed/chart/ ,我同样是用 mixin 方法hack 路由离开时候 销毁不需要缓存的组件,我要做到的是从父级到子集路由,父级被缓存,其他情况都被销毁,这样我们只要控制路由就行了,不用增加任何的属性什么的,我比较懒;

// 支持页面保持
Vue.mixin({
  beforeRouteLeave(to, from, next) {

    if (!to.path.startsWith(from.path)) this.$destroy();

    next();

  }
});

@wanyaxing 谢谢,你的代码对我非常有用。我参考一下;

我发现确实是缓存没有被销毁导致的。尽力在和 @LinusBorg 沟通

@Codezero123
Copy link

Codezero123 commented Dec 3, 2019

tab切换的时候缓存 关闭缓存要销毁及下次打开重新加载 多重嵌套子路由页面也是

@heng1234 你好你这个问题解决了吗,哪位这个问题可以留个联系方式指导一下吗

@heng1234
Copy link

heng1234 commented Dec 4, 2019 via email

@bigfool-cn
Copy link

@wanyaxing 你这种对于三级路由缓存不起效,比如vue-element-admin里面,开启多个三级tag标签的时候,切换tag标签不会销毁缓存组件,但是只开启一个三级路由tag标签,是可以销毁的。比如开启下面的menu1-0 和menu1-1。
路由。
{ path: '/nested', component: Layout, redirect: '/nested/menu1/menu1-1', name: 'Nested', meta: { title: 'Nested Routes', icon: 'nested' }, children: [ { path: 'menu1', component: () => import('@/views/nested/menu1/index'), // Parent router-view name: 'Menu1', meta: { title: 'Menu 1' }, redirect: '/nested/menu1/menu1-1', children: [ { path: 'menu1-0', component: () => import('@/views/nested/menu1/menu1-0'), name: 'Menu1-0', meta: { title: 'Menu 1-0', noCache: true } }, { path: 'menu1-1', component: () => import('@/views/nested/menu1/menu1-1'), name: 'Menu1-1', meta: { title: 'Menu 1-1' } }, { path: 'menu1-2', component: () => import('@/views/nested/menu1/menu1-2'), name: 'Menu1-2', redirect: '/nested/menu1/menu1-2/menu1-2-1', meta: { title: 'Menu 1-2' }, children: [ { path: 'menu1-2-1', component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1'), name: 'Menu1-2-1', meta: { title: 'Menu 1-2-1' } }, { path: 'menu1-2-2', component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2'), name: 'Menu1-2-2', meta: { title: 'Menu 1-2-2' } } ] }, { path: 'menu1-3', component: () => import('@/views/nested/menu1/menu1-3'), name: 'Menu1-3', meta: { title: 'Menu 1-3' } } ] } ] }

`Vue.mixin({
beforeRouteLeave:function(to, from, next){
if (from.meta.noCache) {
if (this.$vnode && this.$vnode.data.keepAlive) {
if (this.$vnode.parent && this.$vnode.parent.componentInstance && this.$vnode.parent.componentInstance.cache) {

      if (this.$vnode.componentOptions) {
        var key = this.$vnode.key == null
          ? this.$vnode.componentOptions.Ctor.cid + (this.$vnode.componentOptions.tag ? `::${this.$vnode.componentOptions.tag}` : '')
          : this.$vnode.key;
        var cache = this.$vnode.parent.componentInstance.cache;
        var keys = this.$vnode.parent.componentInstance.keys;
        if (cache[key]) {
          if (keys.length) {
            var index = keys.indexOf(key);
            if (index > -1) {
              keys.splice(index, 1);
            }
          }
          delete cache[key];
        }
      }
    }
    this.$destroy();
  }
}
next();

},
});`

@wanyaxing
Copy link

思路就是这么个思路,思路是没有问题的,具体何时调用何时销毁缓存,得看你业务中具体实现。

@Lynn-cc
Copy link

Lynn-cc commented Jan 15, 2020

我们业务这边这种场景应该很场景吧:
1、浏览了几个页面,需要缓存
2、点击了退出,需要清除所有的缓存
3、登录后有其他报错跳转提示,这些页面都不做缓存
4、登录成功,新的页面继续缓存

现在发现到2的时候无法清除所有缓存,把keep-alive的max值放到了vuex并设置为了1还是无效,看vue开发者工具里还是有缓存页面的。
我这边还有更奇怪的是,在3里其他非登录页面跳转,会触发1里面的缓存页面的mounted,而且看开发者工具,这些页面都是inactive的,哎,这导致页面逻辑各种问题。
找了好久,还是不知道为啥

@wanyaxing
Copy link

我们业务这边这种场景应该很场景吧:
1、浏览了几个页面,需要缓存
2、点击了退出,需要清除所有的缓存
3、登录后有其他报错跳转提示,这些页面都不做缓存
4、登录成功,新的页面继续缓存

现在发现到2的时候无法清除所有缓存,把keep-alive的max值放到了vuex并设置为了1还是无效,看vue开发者工具里还是有缓存页面的。
我这边还有更奇怪的是,在3里其他非登录页面跳转,会触发1里面的缓存页面的mounted,而且看开发者工具,这些页面都是inactive的,哎,这导致页面逻辑各种问题。
找了好久,还是不知道为啥

你这种场景里啊,在2的时候,应该考虑直接刷新页面,是最保险也最直接的方案。

@wyc2025
Copy link

wyc2025 commented Nov 6, 2020

因为includes对应的是组件的name,如果多个路由对应一个组件,怎么办呢?有什么办法可以给同一个组件命不同的名字吗?

@hsl727261250
Copy link

@leixu2txtek 我已经放弃了那个PR,通过强行清除缓存的方法,我变相得实现了动态删除缓存组件的功能。
我目前全站使用缓存,通过拦截页面离开的路由事件来根据业务逻辑实现删除缓存的功能,以下代码片段供参考:

  • 将router-view放到keep-alive中,默认全站默认使用缓存。
    <keep-alive><router-view class="transit-view"></router-view></keep-alive>
  • 我在routes里将所有的页面进行了分层。如meta.rank代表页面层次,如1.5>2.5>3.5意味着从第一层进入第二层进入第三层页面。
routes: [
{   path: '/', redirect:'/yingshou', },
{   path: '/yingshou',                meta:{rank:1.5,isShowFooter:true},          },
{   path: '/contract_list',           meta:{rank:1.5,isShowFooter:true},          },
{   path: '/customer',                meta:{rank:1.5,isShowFooter:true},          },
{   path: '/wode',                    meta:{rank:1.5,isShowFooter:true},          },
{   path: '/yingfu',                  meta:{rank:1.5,isShowFooter:true},          },
{   path: '/yingfu/pact_list',        meta:{rank:2.5},                            },
{   path: '/yingfu/pact_detail',      meta:{rank:3.5},                            },
{   path: '/yingfu/expend_view',      meta:{rank:4.5},                            },
{   path: '/yingfu/jizhichu',         meta:{rank:5.5},                            },
{   path: '/yingfu/select_pact',      meta:{rank:6.5},                            },
{   path: '/yingfu/jiyingfu',         meta:{rank:7.5},                            },
]
  • 因为所有页面都会缓存,所以核心思路是【何时销毁缓存?】。我的设计是:同层级页面切换或进入下一层页面都会保留当前页缓存,【返回上一层页面时则销毁当前页面缓存】。
  • 所以我在main.js里,使用Vue.mixin的方法拦截了路由离开事件,并在该拦截方法中实现了销毁页面缓存的功能。核心代码如下:

Vue.mixin({
    beforeRouteLeave:function(to, from, next){
        if (from && from.meta.rank && to.meta.rank && from.meta.rank>to.meta.rank)
        {//如果返回上一层,则摧毁本层缓存。
            if (this.$vnode && this.$vnode.data.keepAlive)
            {
                if (this.$vnode.parent && this.$vnode.parent.componentInstance && this.$vnode.parent.componentInstance.cache)
                {
                    if (this.$vnode.componentOptions)
                    {
                        var key = this.$vnode.key == null
                                    ? this.$vnode.componentOptions.Ctor.cid + (this.$vnode.componentOptions.tag ? `::${this.$vnode.componentOptions.tag}` : '')
                                    : this.$vnode.key;
                        var cache = this.$vnode.parent.componentInstance.cache;
                        var keys  = this.$vnode.parent.componentInstance.keys;
                        if (cache[key])
                        {
                            if (keys.length) {
                                var index = keys.indexOf(key);
                                if (index > -1) {
                                    keys.splice(index, 1);
                                }
                            }
                            delete cache[key];
                        }
                    }
                }
            }
            this.$destroy();
        }
        next();
    },
});

总结:其实就是通过页面组件所在的上层keepAlive组件,暴力操控该对象中的cache列表。。。
简单又直接,虽然不是很优雅,然而很好用,哈哈:)
当然还是希望官方能支持API出来更好。

但是这样内存还是不会释放,我关掉keepalive就没事,加上keepalive然后手动移除缓存并销毁内存还是一直在上涨,不知道有没有关注这方面?

目前来看这是最好的解决方法. 尤其是需要打开多个同组件不同参数的标签页时.

@F5F5
Copy link

F5F5 commented Jan 11, 2021

@leixu2txtek 我已经放弃了那个PR,通过强行清除缓存的方法,我变相得实现了动态删除缓存组件的功能。
我目前全站使用缓存,通过拦截页面离开的路由事件来根据业务逻辑实现删除缓存的功能,以下代码片段供参考:

  • 将router-view放到keep-alive中,默认全站默认使用缓存。
    <keep-alive><router-view class="transit-view"></router-view></keep-alive>
  • 我在routes里将所有的页面进行了分层。如meta.rank代表页面层次,如1.5>2.5>3.5意味着从第一层进入第二层进入第三层页面。
routes: [
{   path: '/', redirect:'/yingshou', },
{   path: '/yingshou',                meta:{rank:1.5,isShowFooter:true},          },
{   path: '/contract_list',           meta:{rank:1.5,isShowFooter:true},          },
{   path: '/customer',                meta:{rank:1.5,isShowFooter:true},          },
{   path: '/wode',                    meta:{rank:1.5,isShowFooter:true},          },
{   path: '/yingfu',                  meta:{rank:1.5,isShowFooter:true},          },
{   path: '/yingfu/pact_list',        meta:{rank:2.5},                            },
{   path: '/yingfu/pact_detail',      meta:{rank:3.5},                            },
{   path: '/yingfu/expend_view',      meta:{rank:4.5},                            },
{   path: '/yingfu/jizhichu',         meta:{rank:5.5},                            },
{   path: '/yingfu/select_pact',      meta:{rank:6.5},                            },
{   path: '/yingfu/jiyingfu',         meta:{rank:7.5},                            },
]

复制到剪切板

  • 因为所有页面都会缓存,所以核心思路是【何时销毁缓存?】。我的设计是:同层级页面切换或进入下一层页面都会保留当前页缓存,【返回上一层页面时则销毁当前页面缓存】。
  • 所以我在main.js里,使用Vue.mixin的方法拦截了路由离开事件,并在该拦截方法中实现了销毁页面缓存的功能。核心代码如下:

Vue.mixin({
    beforeRouteLeave:function(to, from, next){
        if (from && from.meta.rank && to.meta.rank && from.meta.rank>to.meta.rank)
        {//如果返回上一层,则摧毁本层缓存。
            if (this.$vnode && this.$vnode.data.keepAlive)
            {
                if (this.$vnode.parent && this.$vnode.parent.componentInstance && this.$vnode.parent.componentInstance.cache)
                {
                    if (this.$vnode.componentOptions)
                    {
                        var key = this.$vnode.key == null
                                    ? this.$vnode.componentOptions.Ctor.cid + (this.$vnode.componentOptions.tag ? `::${this.$vnode.componentOptions.tag}` : '')
                                    : this.$vnode.key;
                        var cache = this.$vnode.parent.componentInstance.cache;
                        var keys  = this.$vnode.parent.componentInstance.keys;
                        if (cache[key])
                        {
                            if (keys.length) {
                                var index = keys.indexOf(key);
                                if (index > -1) {
                                    keys.splice(index, 1);
                                }
                            }
                            delete cache[key];
                        }
                    }
                }
            }
            this.$destroy();
        }
        next();
    },
});

复制到剪切板
总结:其实就是通过页面组件所在的上层keepAlive组件,暴力操控该对象中的cache列表。。。
简单又直接,虽然不是很优雅,然而很好用,哈哈:)
当然还是希望官方能支持API出来更好。

但是这样内存还是不会释放,我关掉keepalive就没事,加上keepalive然后手动移除缓存并销毁内存还是一直在上涨,不知道有没有关注这方面?

我也发现了这个问题,在论坛上提了个问
https://forum.vuejs.org/t/keepalive/109030
不知道有没有大佬能解答一下。。。

@Aaminly
Copy link

Aaminly commented Jul 5, 2021

我这里的场景是点击导航的时候不缓存,但是页面提供了一个返回上级页面,这时取缓存;且详情页返回到列表页也取缓存,目前是实现了需求。

const cacheThis = new Map();
Vue.mixin({
    async beforeRouteLeave(to, from, next) {
        const isNavClick = (await sessionStorage.getItem('isNavClick')) === '1'
        if (isNavClick) {
            if (cacheThis.has(to.name)) {
                cacheThis.get(to.name).$destroy()
            } else {
                cacheThis.set(from.name, this)
            }
        }
        sessionStorage.setItem('isNavClick', '0');
        next()
    }
})

原理就是通过mixin混入一个组件内路由跳转前的守卫,缓存当前组件的this实例到一个map对象里,当点击导航的时候获取一下是否缓存了当前要去的这个实例,如果有,则调用这个实例的destory销毁缓存,达到重新渲染的目的。其他的情况都取keep-alive缓存。

@elewen
Copy link

elewen commented Jul 13, 2021

讨论了快4年了,这个问题还没解决啊???比较明显的一个问题是 keep-alive 应该缺少两个必不可少的配套方法:clear 方法用来清空 keep-alive 实例所属的所有已缓存组件或页面;remove() 方法用来移除 keep-alive 实例所属的某个已缓存组件或页面;

@elewen
Copy link

elewen commented Jul 14, 2021

暴力操作 keys 和 cache,并用 $destroy 销毁实例,很好用。

@zero7u
Copy link

zero7u commented Jul 31, 2021

希望官方打开并解决,确实有问题!
“多个路由对应一个组件” 这不是include能解决的事

@turkyden
Copy link

turkyden commented Oct 24, 2021

How can i destory the component cache by myself ?

In this way ! @elewen @zero7u

<!-- Tabs.vue -->
<template>
  <router-link>
     Tab A
     <span @click.prevent.stop="closeSelectedTag(tag)" />
   </router-link>
</template>
<script>
export default {
  computed: {
    cache: {
      get() {
        if (!this.$route.matched[1]) return 
        const instances = this.$route.matched[1].instances;
        return instances.default.$vnode.parent.componentInstance.cache;
      },
      set(val) {
        this.$route.matched[1].instances.default.$vnode.parent.componentInstance.cache = val
      }
    }
  },
  methods: {
    closeSelectedTag(view) {
      // Remove selected tag 
      // ...
      // Remove the cache from cache
      const cache = this.cache;
      const str = RegExp('.*' + view.fullPath);
      let key = '';
      Object.keys(cache).forEach(el => {
        if (str.test(el)) {
          key = el;
        }
      });
      delete cache[key];
    }
  }
}
</script>

@baohangxing
Copy link

讨论了快4年了,这个问题还没解决啊???比较明显的一个问题是 keep-alive 应该缺少两个必不可少的配套方法:clear 方法用来清空 keep-alive 实例所属的所有已缓存组件或页面;remove() 方法用来移除 keep-alive 实例所属的某个已缓存组件或页面;

不能赞同更多

@betgar
Copy link

betgar commented Oct 28, 2021

Custom cache strategy and matching rules for KeepAlive vuejs/rfcs#284

@turkyden
Copy link

b

@zhangchugao
Copy link

@jkzing 如果我同一个组件加载了两次,一个需要缓存,一个不需要缓存怎么弄,他们的组件name是一样的呀

我也是这个疑问,include无法满足这个需求,多个路由页面对应一个组建,那就只有一个组件name,咋办?

自己实现一个keep-alive组件替换vue的keep-alive,这篇知乎文章有介绍:https://zhuanlan.zhihu.com/p/269385782,但是需要自己将keep-alive的缓存key从name修改成根据路径path进行缓存。

@fanfanjiang
Copy link

@zhangchugao 你好,你发的链接好像失效了,能再贴一下吗,谢谢

@zhangchugao
Copy link

@zhangchugao 你好,你发的链接好像失效了,能再贴一下吗,谢谢

没有失效的。https://zhuanlan.zhihu.com/p/269385782

@zhongguodong
Copy link

zhongguodong commented May 10, 2022

@zhangchugao 你好,你的解决方案非常好,和我的问题一模一样。但是有个小小问题,路由名字也是一样的。路由地址也是一样的,但是参数不一样,两个页面的,分别缓存起来。

例如:
http://localhost/#/ehr/parameter/index/3
http://localhost/#/ehr/parameter/index/13

路由信息:

  {
    path: "/ehr/parameter",
    component: Layout,
    hidden: true,
    children: [
      {
        path: "index/:wid(\\d+)",
        component: resolve =>
          require(["@/views/datamodel/winparameter/index"], resolve),
        name: "WinParameter",
        meta: { title: "加载参数", activeMenu: "/datamodel/winparameter" }
      }
    ]
  }

标签卡的组件页面,全部都空白页面了
image

@zhangchugao
Copy link

@zhangchugao 你好,你的解决方案非常好,和我的问题一模一样。但是有个小小问题,路由名字也是一样的。路由地址也是一样的,但是参数不一样,两个页面的,分别缓存起来。

例如: http://localhost/#/ehr/parameter/index/3 http://localhost/#/ehr/parameter/index/13

路由信息:

  {
    path: "/ehr/parameter",
    component: Layout,
    hidden: true,
    children: [
      {
        path: "index/:wid(\\d+)",
        component: resolve =>
          require(["@/views/datamodel/winparameter/index"], resolve),
        name: "WinParameter",
        meta: { title: "加载参数", activeMenu: "/datamodel/winparameter" }
      }
    ]
  }

标签卡的组件页面,全部都空白页面了 image

你好,我这边测试了,发现没有问题,请问你是否修改了自定义keep-alive组件js的缓存key从name修改为更具path路径缓存,原作者贴的代码当中使用的组件的name来缓存对应的每个路由的。我修改如下图所示:
image
你可以查看你是否修改了图片中的代码。
1652163725
1652163725(1)

@zhongguodong
Copy link

@zhangchugao 你好,你的解决方案非常好,和我的问题一模一样。但是有个小小问题,路由名字也是一样的。路由地址也是一样的,但是参数不一样,两个页面的,分别缓存起来。
例如: http://localhost/#/ehr/parameter/index/3 http://localhost/#/ehr/parameter/index/13
路由信息:

  {
    path: "/ehr/parameter",
    component: Layout,
    hidden: true,
    children: [
      {
        path: "index/:wid(\\d+)",
        component: resolve =>
          require(["@/views/datamodel/winparameter/index"], resolve),
        name: "WinParameter",
        meta: { title: "加载参数", activeMenu: "/datamodel/winparameter" }
      }
    ]
  }

标签卡的组件页面,全部都空白页面了 image

你好,我这边测试了,发现没有问题,请问你是否修改了自定义keep-alive组件js的缓存key从name修改为更具path路径缓存,原作者贴的代码当中使用的组件的name来缓存对应的每个路由的。我修改如下图所示: image 你可以查看你是否修改了图片中的代码。 1652163725 1652163725(1)

是的,我刚刚改好了,vue2测试了,有vue3版本的吗?官方一直不处理这个问题,郁闷。

@zhangchugao
Copy link

@zhangchugao 你好,你的解决方案非常好,和我的问题一模一样。但是有个小小问题,路由名字也是一样的。路由地址也是一样的,但是参数不一样,两个页面的,分别缓存起来。
例如: http://localhost/#/ehr/parameter/index/3 http://localhost/#/ehr/parameter/index/13
路由信息:

  {
    path: "/ehr/parameter",
    component: Layout,
    hidden: true,
    children: [
      {
        path: "index/:wid(\\d+)",
        component: resolve =>
          require(["@/views/datamodel/winparameter/index"], resolve),
        name: "WinParameter",
        meta: { title: "加载参数", activeMenu: "/datamodel/winparameter" }
      }
    ]
  }

标签卡的组件页面,全部都空白页面了 image

你好,我这边测试了,发现没有问题,请问你是否修改了自定义keep-alive组件js的缓存key从name修改为更具path路径缓存,原作者贴的代码当中使用的组件的name来缓存对应的每个路由的。我修改如下图所示: image 你可以查看你是否修改了图片中的代码。 1652163725 1652163725(1)

是的,我刚刚改好了,vue2测试了,有vue3版本的吗?官方一直不处理这个问题,郁闷。
不好意思,暂时没有,你可以自己尝试。

@Hansomeble
Copy link

Hansomeble commented Oct 11, 2022 via email

@mogazheng
Copy link

真的服了,到现在还不能手动清keepalive?vue3又把$destroy去了,嘛呢,开倒车呢?

@betgar
Copy link

betgar commented Oct 11, 2022

vuejs/rfcs#284

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests