vue-router 总是创建一个新的 Component 实例

Posted

技术标签:

【中文标题】vue-router 总是创建一个新的 Component 实例【英文标题】:vue-router creates always a new Component instance 【发布时间】:2018-08-31 15:29:54 【问题描述】:

我在 vue-router 中发现了一个让我很受触动的问题。 当我在我的路线之间切换时,总是会创建一个新的组件实例。此外,旧实例不会被删除,而是在后台运行!

我希望当我打开一个路由时,旧的组件会被销毁或停止运行。

是否有解决该问题的解决方法?

这是一个小提琴:https://jsfiddle.net/4xfa2f19/5885/

let foo = 
    template: '<div>Foo</div>',
    mounted() 
        console.log('Mount Foo with uid: ' + this._uid);
        setInterval(() => console.log('Instance ' + this._uid + ' of Foo is running'), 500);
    
;

let bar = 
    template: '<div>Bar</div>',
    mounted() 
        console.log('Mount Bar with uid: ' + this._uid);
        setInterval(() => console.log('Instance ' + this._uid + ' of Bar is running'), 500);
    
;


const router = new VueRouter(
    routes: [
         path: '/user/foo', component: foo ,
         path: '/user/bar', component: bar 
    ]
);


const app = new Vue( router ).$mount('#app');

【问题讨论】:

Update VueJs component on route change的可能重复 【参考方案1】:

有两种方法可以解决这个问题:

destroy 挂钩中正确清理

如果您使用任何外部事件侦听器,例如 setIntervaladdEventListener 等,您还需要在组件被销毁时取消注册它们,例如:


    name: '...',
    template: '...',
    data() 
        return 
            interval: undefined,
            timeout: undefined
        ;
    ,
    mounted() 
        interval = setInterval(() => console.log('Instance ' + this._uid + ' of myself is running'), 500);
        timeout = setTimeout(() => console.log('Instance ' + this._uid + ' of myself is running'), 500);
        document.addEventListener('click', this.onOutsideClick);
    ,
    beforeDestroy() 
        // Cleanup interval
        clearInterval(interval);
        // Cleanup any pending timeouts
        clearTimeout(timeout);
        // Cleanup any event listeners outside the root of the element
        document.removeEventListener('click', this.onOutsideClick);
    ,
    methods: 
        onOutsideClick() 
            ...
        
    

使用 keep-alive 使组件保持活动状态

当使用 keepalive 时,Vue 会缓存你的组件,并在后台保持它处于活动状态,这意味着永远只会存在一个实例。如果您有大量路线,这可能会消耗更多内存

<keep-alive>
    <router-view></router-view>
</keep-alive>

【讨论】:

【参考方案2】:

当我在我的路由之间切换时,总是会创建一个新的组件实例。

这是意料之中的。您可以通过&lt;keep-alive&gt; 组件保持实例处于活动状态并重新使用它们,但这通常不是必需的,如果是这样,需要特别注意重新启动所有需要的重用组件的本地状态。

创建一个新实例更加简洁,因此是默认行为。

此外,旧实例不会被删除,而是在后台运行!

这不是预期的。先前的实例被销毁。

setInterval(() => console.log('Instance ' + this._uid + ' of Foo is running'), 500);

好吧,由于这个间隔回调包含对组件实例的引用,它不能被浏览器垃圾收集,所以你要让它们保持活动状态,而不是 Vue。

如果没有那个间隔,我希望实例在路由器销毁它们后被垃圾收集。

【讨论】:

谢谢。有没有办法检查是否触发了“破坏”,以便我可以清除间隔? 只需使用 Vue 的生命周期钩子即可。你已经知道mounted,所以你也知道beforeDestroy? vuejs.org/v2/api/#beforeDestroy【参考方案3】:

这里说明了同样的问题:https://github.com/vuejs/vuex/issues/1580

作为一种解决方法,您可以使用过渡模式 out-in。罗兰达

<transition mode="out-in">    <router-view></router-view> </transition>

【讨论】:

【参考方案4】:

在 Vue 3 中,语法发生了变化。告诉 Vue Router 让所有组件保持活动状态的解决方案是:

<router-view v-slot=" Component ">
    <keep-alive>
        <component :is="Component" />
    </keep-alive>
</router-view>

如果你只想让某个人活着,那么你可以使用这个:

<router-view v-slot=" Component ">
    <keep-alive include="foo">
        <component :is="Component" />
    </keep-alive>
</router-view>

或者确保一个人没有活着(但所有其他人都活着),这样做:

<router-view v-slot=" Component ">
    <keep-alive exclude="foo">
        <component :is="Component" />
    </keep-alive>
</router-view>

【讨论】:

以上是关于vue-router 总是创建一个新的 Component 实例的主要内容,如果未能解决你的问题,请参考以下文章

vue-router组件里面点击一个按钮跳转到一个新的组件该怎么实现

vue动态添加路由,跳转页面时,页面报错路由重复:vue-router.esm.js?8c4f:16 [vue-router] Duplicate named routes definition: {

vue动态添加路由,跳转页面时,页面报错路由重复:vue-router.esm.js?8c4f:16 [vue-router] Duplicate named routes definition: {

使用 UserPrincipal 类创建新的 AD-LDS 用户总是失败

vue路由实例

Azure管道 - 通过json导入任务组总是创建一个新的而不是更改现有的