web-dev-qa-db-ja.com

Vue-router reloadコンポーネント

それぞれ3つのコンポーネントをロードするいくつかのルートがあります。 2つのコンポーネントはすべてのルートで同じです。これらのルート間を移動するとき、新しいデータを渡し、コンポーネントの一部の初期化イベントで、そのコンポーネントのデータを入力して、UIに反映するようにします。また、ロードされているコンポーネントのbootstrapアニメーションをリトリガーします。それをどうやってやろうか。現時点では、コンポーネントのライフサイクルのどこでデータを取得し、この新しいデータでコンポーネントを再レンダリングするのかわからないからです。具体的にmyapps/1と/ newapp /には、メインビューコンポーネントとサイドバーコンポーネントがあります。/newapp/URLで、サイドバーのすべてのアイコンを赤にし(メインビューには何も表示されていません)、メインビューを空にする必要があります。 myapps/1で、サーバーからメインビューにデータをロードし、すべてが埋まっている場合は、サイドバーのアイコンを緑色にする必要があります。今、myapps/1をロードし、サイドバーの2番目のアイテムをクリックすると、メインビューが2番目のビューに変わります。その後、router.Push( "/ newapp /);とサイドバーは2番目のアイテムと2番目のメインビューに留まります。したがって、router.Push("/myapps/");はサイドバーとメインビューをリロードしません。

編集:

ここで、私のルート、サイドバー、デフォルトが同じであることがわかります。

_ const routes = [
    {
        path: "/myapps/newproject",
        components: {
            default: ProjectMain,
            "breadcrumbs": BreadcrumbsNewProject,
            "sidebar": SidebarProject
        }
    },
    {
        path: "/myapps/:id",
        components: {
            default: ProjectMain,
            "breadcrumbs": BreadcrumbsCurrentProject,
            "sidebar": SidebarProject
        }
    },
    {
        path: "/myapps/newversion/:id",
        components: {
            default: ProjectMain,
            "breadcrumbs": BreadcrumbsNewVersion,
            "sidebar": SidebarProject
        }
    }
];
_

これは私のProjectMain.vueです

_<template>
    <div class="wrapper wrapper-content">
        <component :is="currentProjectMain"></component>
    </div>
</template>
_

これはindex.htmlの私のルータービューです:

_<router-view name="sidebar"></router-view>
_

そして、index.htmlにもう1つ、デフォルトのものがあります。

_<router-view></router-view>
_

サイドバーの項目をクリックすると、ProjectMainにイベントを発行してコンポーネントを切り替えます。このように:サイドバーで:

_eventBus.$emit("currentProjectMainChanged", "appOverview");
_

または

_eventBus.$emit("currentProjectMainChanged", "appSettings");
_

そしてProjectMainより:

_eventBus.$on("currentProjectMainChanged", function(data){
                if(data === "appOverview"){
                    self.currentProjectMain = CurrentProjectAppOverview;
                }else if(data === "appSettings"){
                    self.currentProjectMain = CurrentProjectSettings;
                }
            });
_

「/ myapps /:id」に到達した場合。サイドバーとProjectMainをロードし、このbootstrapクラス:_<div class="animated fadeInUp">_でサイドバーとProjectMainの小さなアニメーションを取得し、両方のコンポーネントがライフサイクル全体を通過しました。

デフォルトでは、サイドバーでappOverviewが選択されており、CurentProjectAppOverview.vueはProjectMainのコンポーネントとしてロードされます。サイドバーのappSettingsをクリックし、サイドバーのその項目にクラスを追加して選択済みとしてマークし、ProjectMainでCurrentProjectSettings.vueがコンポーネントとしてロードされるよりも。

しかし、パンくずリストには「/ myapps/newversion /:id」に移動するボタンがありますここに問題があります。クリックして「/ myapps/newversion /:id」(router.Push("/myapps/newversion/" + id);)に移動すると、サイドバーの2番目の項目が選択されたまま(appSettings)で、ProjectMainでCurrentProjectSettings.vueがロードされたままになり、取得できませんサイドバーとProjectMainのbootstrapアニメーション、およびコンポーネントはライフサイクルを通過しません。

「/ myapps/newversion /:id」に移動するためにボタンをクリックするときにここで欲しいのは、私のbootstrapアニメーション(_<div class="animated fadeInUp">_)です。ライフサイクル。そして、サイドバーでデフォルトのアイテムを選択し(したがってappOverview)、デフォルトのコンポーネントをProjectMainにロードします(したがってCurentProjectAppOverview.vue)。

サイドバーの各アイテムには色付きのボタンがあります。 「/ myapps /:id」から「/ myapps/newversion /:id」に移動する場合、サーバーからCurrentProjectAppOverview.vueにデータをロードし、すべてのデータが満たされている場合はサイドバーのボタンを緑、そうでなければ赤になります。

つまり、この2つのルート間を移動するとき、データをロードして必要なフィールドに入力できるようにしたいので、bootstrapアニメーションとデフォルトビューを選択してロードし、全体を通過する必要がありますライフサイクル。現在、ルーターはそれらをそのまま再利用しています。

そのため、「ReloadComponent:true」、またはコンポーネントを破棄して再作成します。

SidebarProject.vueとProjectMain.vueを複製して名前を変更し、各ルートで基本的にコピーをロードできますが、異なる.vueファイルに同じコードを記述する必要があります。

YouComponent.route.canReuseをfalseに設定するオプションが存在する前に、これは私が望むことをするでしょうが、最新バージョンでは削除されます。

10
dari0h

部分的にこれに感謝: https://forum.vuejs.org/t/vue-router-reload-component/4429

私に合った解決策を思いつきました:

最初に、コンポーネントのロード時にアニメーションを再トリガーするbootstrap=に使用される新しい関数をjQueryに追加しました。

_$.fn.redraw = function(){
    return $(this).each(function(){
        var redraw = this.offsetHeight;
    });
};
_

コンポーネント内:

_export default{
        created:function(){
            this.onCreated();
        },
        watch: {
            '$route' (to, from) {
                //on route change re run: onCreated
                this.onCreated();

                //and trigger animations again
                $("#breadcrumbsCurrentProject").find(".animated").removeClass("fadeIn").redraw().addClass("fadeIn");
            }
        }
}
_

コンポーネントがロードされ、ルートがリロードされるか、同じルートのIDが変更されても、コンポーネントが同じままである場合、onCreated();メソッドを呼び出します。メソッドを再度呼び出します。これにより、新しいデータが処理されます。

bootstrapアニメーションを再トリガーする場合は、アプリの起動時にjQueryに追加するredraw();関数を使用します。これにより、URLの変更時にアニメーションがトリガーされます。

_$("#breadcrumbsCurrentProject").find(".animated").removeClass("fadeIn").redraw().addClass("fadeIn");
_
7
dari0h

私は同じ問題に直面していました。見つけた答えを引用しますが、これは本当にシンプルで素晴らしいものです。最も簡単な解決策は、:key属性を追加することです:

<router-view :key="$route.fullPath"></router-view>

これは、Vue同じコンポーネントがアドレス指定されている場合、ルーターは変更を認識しません。

14
Gkiokan

Vue-routerを使用しているようです。

私はあなたのコードを持っていませんが、私がこれをどのように扱ったかを示すことができます。 named-viewsを参照

これはbundle.jsファイルのルーターマップです。

const router = new VueRouter({
routes: [
    { path: '/',
      components: {
        default: dashboard,
        altside: altSide,
        toolbar: toolbar
      },
    },
    { path: '/create',
      components: {
        default: create,
        altside: altSide,
        toolbar: toolbar
      },
    },
    { path: '/event/:eventId', 
        name: 'eventDashboard',
        components: { 
            default: eventDashboard,
            altside: altSide,
            toolbar: eventToolbar,
        },
        children: [
            { path: '/', name: 'event', component: event },
            { path: 'tickets', name: 'tickets', component: tickets},
            { path: 'edit', name: 'edit', component: edit },
            { path: 'attendees', name: 'attendees', component: attendees},
            { path: 'orders', name: 'orders', component: orders},
            { path: 'uploadImage', name: 'upload', component: upload},
            { path: 'orderDetail', name: 'orderDetail', component: orderDetail},
            { path: 'checkin', name: 'checkin', component: checkin},
        ],
    }
]
})

「default」、「altside」、「toolbar」の名前付きビューがあります。各パスの名前付きビューにコンポーネントを割り当てています。

この後半は、名前を割り当てる親コンポーネントにあります

<router-view  name="toolbar"></router-View>   

親テンプレートは次のとおりです。

<template>

    <router-view class="view altside" name="altside"></router-view>
    <router-view class="view toolbar" name="toolbar"></router-view>
    <router-view class="view default"></router-view>
</template>

だから、私がやったことは、親テンプレートにルータービューの名前付きビューを見るように言ったということです。そして、パスに基づいて、router-mapで指定したコンポーネントをプルします。

「/」パスツールバー==ツールバーコンポーネントですが、「/作成」パスツールバー= eventToolbarコンポーネント。

デフォルトのコンポーネントは動的です。これにより、ツールバーまたは代替コンポーネントを交換せずに子コンポーネントを使用できます。

3
retrograde

これは私が思いついたものです:

_import ProjectMain from './templates/ProjectMain.vue';
import SidebarProject from './templates/SidebarProject.vue';
_

//新しいオブジェクトが$.extend({}, OriginalObject);で個別の.vueファイルとして扱われるようにオブジェクトを浅くコピーします//これは基本的に同じ.vueファイルを作成する必要はありませんが、vue-routerはそれらが異なるため、それらのファイルをリロードします

_const ProjectMainA = $.extend({}, ProjectMain);
const ProjectMainB = $.extend({}, ProjectMain);
const ProjectMainC = $.extend({}, ProjectMain);
const SidebarProjectA = $.extend({}, SidebarProject);
const SidebarProjectB = $.extend({}, SidebarProject);
const SidebarProjectC = $.extend({}, SidebarProject);

const routes = [
{
path: "/myapps/newproject",
components: {
default: ProjectMainA,
"breadcrumbs": BreadcrumbsNewProject,
"sidebar": SidebarProjectA
}
},
{
path: "/myapps/:id",
components: {
default: ProjectMainB,
"breadcrumbs": BreadcrumbsCurrentProject,
"sidebar": SidebarProjectB
}
},
{
path: "/myapps/newversion/:id",
components: {
default: ProjectMainC,
"breadcrumbs": BreadcrumbsNewVersion,
"sidebar": SidebarProjectC
}
}
];
_

これは基本的に、vue-routerに異なる.vueコンポーネントをロードしていると思わせますが、実際は同じです。そのため、コンポーネント、アニメーション、ライフサイクルのリロードなど、必要なすべてのものを取得できます。複数の類似または同一のコンポーネントを記述する必要はありません。どう思いますか、これがベストプラクティスかどうかはわかりません。

1
dari0h