Vue-router重新加载组件

时间:2016-12-23 17:29:08

标签: vue.js vue-router

我有一些路由,每个路由加载3个组件。所有路线上的两个组件都是相同的。 当我在这些路径之间移动时,我想传递新数据,在组件的某个init事件上,我想填充该组件的数据,以便在UI上反映出来。 此外,我想重新启动正在加载的组件的引导动画。 我该怎么做呢 因为现在,我不知道在组件生命周期中我将获取数据并使用这些新数据重新呈现组件。 具体来说,在myapps / 1和/ newapp /我有一个主视图组件和一个侧边栏组件。在/ newapp / URL中,我希望侧栏上的所有图标都是红色(主视图上没有任何内容已填充),主视图应为空。 在myapps / 1上,我想将服务器中的数据加载到主视图中,如果它全部填满,我希望侧边栏上的图标为绿色。 现在发生了什么我加载myapps / 1,单击侧栏中的第二个项目,主视图更改为第二个视图。然后我router.push(" / newapp /);和侧边栏保持在第二个项目和第二个主视图上。 所以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中有另一个,默认的一个:

<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;
                }
            });

如果我到了&#34; / myapps /:id&#34;。它加载了侧边栏和ProjectMain,我得到了侧边栏和ProjectMain的一些动画,带有这个引导类: <div class="animated fadeInUp">并且两个组件都贯穿整个生命周期。

默认情况下,在侧栏中选择appOverview,CurentProjectAppOverview.vue作为ProjectMain中的组件加载。 我点击边栏中的appSettings,然后将类添加到侧边栏中的该项目以将其标记为已选中,并在ProjectMain中将CurrentProjectSettings.vue作为组件加载。

然后在面包屑中我有一个按钮去&#34; / myapps / newversion /:id&#34; 这是问题所在。当我点击进入&#34; / myapps / newversion /:id&#34; (router.push("/myapps/newversion/" + id);)侧边栏上的第二个项目保持选中状态(appSettings),在ProjectMain中,CurrentProjectSettings.vue仍然加载,我没有得到侧边栏和ProjectMain的引导动画,并且组件没有#39经历他们的生命周期。

当我点击按钮转到&#34; / myapps / newversion /:id&#34;是我的自举动画(<div class="animated fadeInUp">),我希望补充工具栏和ProjectMain完成整个生命周期。我希望在侧边栏上选择默认项目(所以appOverview),并在ProjectMain中加载默认组件(所以CurentProjectAppOverview.vue)。

侧边栏中的每个项目都有彩色按钮。如果我去&#34; / myapps / newversion /:id&#34;来自&#34; / myapps /:id&#34;,我想将服务器中的数据加载到CurrentProjectAppOverview.vue中,如果所有数据都已填满,我希望侧边栏上的按钮为绿色,如果不是,则应为红色

所以简而言之,当我在这两条路线之间移动时,我希望能够加载数据并填充我想要的字段,并且我希望选择并加载引导动画和默认视图,它们应该贯穿整个生命周期。现在路由器只是按原样重用它们。

类似于&#34; ReloadComponent:true&#34;,或者销毁并重新创建组件。

我可以复制SidebarProject.vue和ProjectMain.vue并重命名它们,并且在每个路由中基本上加载一个副本,但这意味着我必须在不同的.vue文件中编写相同的代码。

之前有一个选项可以将YouComponent.route.canReuse设置为false,这可以做我想要的,我认为,但它会在最新版本中删除。

4 个答案:

答案 0 :(得分:6)

我遇到了同样的问题。我将引用一个找到的答案,这非常简单而且很棒。 最简单的解决方案是将:key属性添加到:

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

这是因为如果正在寻址相同的组件,Vue Router不会发现任何变化。使用密钥,对路径的任何更改都将触发使用新数据重新加载组件。

答案 1 :(得分:5)

部分地对此:https://forum.vuejs.org/t/vue-router-reload-component/4429

我提出了一个适合我的解决方案:

首先,我向jQuery添加了一个新函数,用于在组件加载时重新触发bootstrap动画。

$.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");
            }
        }
}

我在组件加载时调用onCreated();方法,当路由重新加载或同一路由的ID发生变化但组件保持不变时,我再次调用该方法。这会处理新数据。

至于重新触发引导动画,我使用redraw();函数,我在应用程序的开头添加到jQuery。这会重新触发URL更改的动画:

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

答案 2 :(得分:3)

看起来你正在使用vue-router。

我没有你的代码,但我可以告诉你我是如何处理的。 See 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},
        ],
    }
]
})

我有“默认”,“altside”和“工具栏”的命名视图我正在为每个路径的命名视图分配一个组件。

此后半部分位于父组件中,您可以在其中指定名称

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

所以,我所做的就是告诉父模板查看路由器视图的命名视图。并根据路径,拉出我在路由器映射中指定的组件。

对于我的'/'路径工具栏==工具栏组件,但在'/ create'路径工具栏= eventToolbar组件中。

默认组件是动态的,这允许我使用子组件而无需交换工具栏或altside组件。

答案 3 :(得分:1)

这就是我提出的:

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

//现在浅层复制对象,以便将新对象视为seperatete .vue文件:$.extend({}, OriginalObject); //这是我不必创建基本相同的.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组件,但它们实际上是相同的。所以我得到了我想要的一切:重新加载组件,动画,生命周期,而且我不必编写多个相似或相同的组件。 你怎么想,我只是不确定这是不是最好的做法。