web-dev-qa-db-ja.com

VueルーターbeforeRouteLeaveはサブコンポーネントを停止しません

簡単な質問があります。ルートが変更されたときにサブコンポーネントをキャンセルしたいだけです。これがサンプルです。親であるホームコンポーネントがあります。そして、それはサブコンポーネントを持っています。マウントされたサブコンポーネントのルート変更時にインターバル機能を停止したいだけです

import Home from "./components/Home.vue";
import Another from "./components/Another.vue";
const routes = [
    { path: '', component: Home },
    { path: '/another', component: Another }
];
const router = new VueRouter({
    routes
});
const app = new Vue({
    router

}).$mount('#app');

そして、これはホームコンポーネントです。 Home.vue

<template>
  <sub-component></sub-component>
</template>
<script type="text/babel">
    import SubComponent from "./components/Subcomponent.vue";
    export default {
       components:{
          'sub-component':SubComponent
       }
    }
</script>

そしてこれはサブコンポーネントです。 Subcomponent.vue

<template>
   <div> Sub component will run a interval </div>
</template>
<script type="text/babel">
    import SubComponent from "./components/Subcomponent.vue";
    export default {
       components:{
          'sub-component':SubComponent
       },
       mounted:function(){
           setInterval(function(){
             console.log("I should cancel when route changed");
           },1000)
       }
    }
</script>

BeforeRouteLeaveメソッドを試しましたが、Home.vueメソッドのみが停止します。

8

(ルートコンポーネント内の)サブコンポーネントを使用しているため、beforeRouteLeaveを直接使用することはできません。

サブコンポーネントは、ルートの子コンポーネントです。したがって、以下のガイドページで説明されているように、子コンポーネント参照を使用して、ルートコンポーネントから子コンポーネントのexitメソッドをトリガーする必要があります。

https://vuejs.org/v2/guide/components.html#Child-Component-Refs

次のように、サブコンポーネントへの参照を作成できます。

_<sub-component ref="mySubComponent"></sub-component>
_

これで、ルートコンポーネントで、次のことができます。

_beforeRouteLeave: function(to, from, next) {
    // Indicate to the SubComponent that we are leaving the route
    this.$refs.mySubComponent.prepareToExit();
    // Make sure to always call the next function, otherwise the hook will never be resolved
    // Ref: https://router.vuejs.org/en/advanced/navigation-guards.html
    next();
}
_

注:ルートコンポーネントは、この例ではprepareToExit()という子サブコンポーネントのメソッドを呼び出します。このメソッドでは、次のようにクリーンアップを実行できます。

_methods: {
    prepareToExit: function() {
        console.log("Preparing to exit sub component, stopping 'twoSecondsTimerEvents'")
        clearInterval(this.twoSecondsTimerEvents)
    }
}
_

実用的な例を次に示します。 https://jsfiddle.net/mani04/crwuxez3/ (コンソールに記録されたすべての詳細)

注意:この例では、Vue 2.1.10およびVue-Router2.2.0(現在の最新バージョン)を使用しています。以前のバージョンでは、 Navigation Guards)周辺にいくつかの問題がありました。 関数。これで完全に解決されました。

編集:代替方法

上記の解決策を投稿した後、私はそれを行うためのより簡単な方法があることに気づきました。サブコンポーネントはbeforeRouteLeaveのようなルート固有のコールバックを取得しない場合がありますが、それでもコンポーネントのライフサイクルに従うVueコンポーネントです。

したがって、 コンポーネントライフサイクル図 に基づいて、タイマーをクリアするために使用できるサブコンポーネントにbeforeDestroyコールバックがあります。

これがあなたがそれをすることができる方法です:

_const SubComponent = Vue.component('sub-component', {
    template: `...`,
    data: function() {...},
    mounted: function() {...},
    // 'prepareToExit' method not required here
    // And also there is no need to handle 'beforeRouteLeave' in parent
    beforeDestroy: function() {
        console.log("Stopping the interval timer")
        clearInterval(this.twoSecondsTimerEvents)
    }
});
_

利点:

  1. 以前のアプローチよりもはるかに簡単です。
  2. 親コンポーネントで子コンポーネントの参照を処理する必要はありません。
  3. 親コンポーネントからクリーンアップメソッドをトリガーする必要はありません。

不利な点はありませんが、宛先ルートに基づいて他のアクションを実行したい場合に備えて、このトリガーはルート変更に正確に関連付けられていません。これがもっと好きなら、これを使うこともできます。

13
Mani