2

keep-alive我有使用路由器中的方法的VUE 应用程序。许多页面只需要加载一次,但某些特定页面需要在每次激活时再次加载。

<template>
  <router-view v-slot="{ Component }">
    <keep-alive max="5">
      <component :is="Component" />
    </keep-alive>
  </router-view>
<template>

我想要做的是缓存中unmount的页面组件,keep-alive当它是deactivated.

/* this is the loaded component */
export default {
  setup() {
    const state=ref({})
    /*init and load data...*/
   
    onDeactivated(()=>{
     //unmount this component ???
    });
    
    return { state };
  },
  components: {},
};

你认为最好的做法是什么?

4

2 回答 2

2

有条件的keep-alive

您可以通过反应集provide为子路由添加/删除自己keep-aliveexclude属性的方法。keepAliveExcludes将 ref 作为计算数组公开给模板(excludeprop 需要Array,而不是Set):

// App.vue
import { provide, reactive, computed } from 'vue'

export default {
  setup() {
    const keepAliveExcludes = reactive(new Set())

    provide('keepAliveExcludes', {
      add: name => keepAliveExcludes.add(name),
      remove: name => keepAliveExcludes.delete(name),
    })

    return {
      keepAliveExcludes: computed(() => Array.from(keepAliveExcludes))
    }
  }
}

在应用模板中,绑定keepAliveExcludes<keep-alive>.exclude

<template>
  <router-view>
    <keep-alive :exclude="keepAliveExcludes">
      ...
    </keep-alive>
  </router-view>
</template>

在子路由中,inject,keepAliveExcludes并在需要时使用组件的名称调用它的add/ remove(例如,通过复选框):

<template>
  <h1>About</h1>
  <div>
    <label>Keep Alive
      <input type="checkbox" v-model="keepAlive">
    </label>
  </div>
</template>

<script>
import { ref, inject, watchEffect } from 'vue'

export default {
  name: 'About',
  setup() {
    const { add: addKeepAliveExclude, remove: removeKeepAliveExclude } = inject('keepAliveExcludes', {})

    const keepAlive = ref(true)
   
    watchEffect(() => {
      if (keepAlive.value) {
        removeKeepAliveExclude?.('About')
      } else {
        addKeepAliveExclude?.('About')
      }
    })

    return { keepAlive }
  },
}
</script>

演示 1

始终排除在keep-alive

如果您需要始终keep-alive缓存中排除组件,您可以简单地静态设置组件名称,而无需上述provide/的复杂性inject

在 app 模板中,指定组件的名称(必须与name组件声明中的 prop 匹配)<keep-alive>.exclude

<template>
  <router-view>
    <keep-alive exclude="About">
      ...
    </keep-alive>
  </router-view>
</template>

演示 2

于 2021-08-31T19:11:08.567 回答
1

@tony19发布了一个很棒的答案,但由于可能存在 VUE 错误(目前我使用 3.2.6),它存在一些问题。

当一个组件在启动后从 keep-alive 中排除,然后在达到 max keep-alive 组件后,VUE 会尝试删除不存在的排除组件。

这会导致错误并停止应用程序。有关该错误的更多信息,请参见下文。

我的解决方案依赖于 tony19 令人惊叹的解决方案。

我没有在加载组件后排除它,而是在加载组件之前向路由器添加了规则。

const routes = [
  /* ... */
  {
    path: "/about",
    name: "AboutPage",
    meta: { excludeKeepAlive: true },
    component: () => import('./../components/AboutPage.vue'),
  }
  /* ... */
];

然后在主APP中;

/* This is the main app */
export default {
  setup() {
    /* ... */
    const keepAliveExcludes = reactive(new Set());

    cont keepAliveExcluder= {
      add: name => keepAliveExcludes.add(name),
      remove: name => keepAliveExcludes.delete(name),
    }
   
    router.beforeEach((to, from, next) => {    
      if(to.meta?.excludeKeepAlive===true){      
        keepAliveExcluder.add(to.name);
      } 
      next();
     });
    /* ... */
   return {
      keepAliveExcludes: computed(() => Array.from(keepAliveExcludes))
    }
   }
}

有关错误的更多信息(可能是错误)

错误发生在runtime-core.esm-bundler.js:2057

Uncaught (in promise) TypeError: Cannot read property 'type' of undefined

VUE 找不到动态排除的组件。

错误截图

于 2021-09-02T08:01:29.770 回答