vue-router始终创建一个新的Component实例

时间:2018-03-22 09:07:05

标签: javascript vue.js routing vue-router

我在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');

4 个答案:

答案 0 :(得分:6)

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

正确清理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>

答案 1 :(得分:2)

  

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

这是预料之中的。你可以保持instanes活着并使用<keep-alive>组件重新使用它们,但这通常不是必需的,如果是这样,需要特别注意重新启动necesseray中所有重用组件的本地状态。

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

  

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

没想到。以前的实例都被销毁了。

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

好吧,因为这个intervall回调包含对组件实例的引用,所以它不能被浏览器垃圾收集,所以你让它们保持活着,而不是Vue。

如果没有这个intervall,我会在路由器销毁它们之后期望垃圾收集。

答案 2 :(得分:0)

同一问题在这里指出:https://github.com/vuejs/vuex/issues/1580

作为解决方法,您可以使用过渡模式输出。罗兰达(Rolandoda)

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

答案 3 :(得分:0)

在 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>