Vue-router 重新加载组件
Vue-router reload components
我有几条路线,每条路线加载 3 个组件。其中两个组件在所有路线上都是相同的。
当我在这些路由之间移动时,我想传递新数据,并且在组件的某些初始化事件上,我想填充该组件的数据,以便它反映在 UI 上。
我还想重新触发正在加载的组件的 bootstrap 动画。
我将如何去做。
因为现在,我不知道在组件生命周期的哪个位置获取数据并使用这些新数据重新呈现组件。
具体来说,在 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;
}
});
如果我到达“/myapps/:id”。它加载了侧边栏和 ProjectMain,我用这个 bootstrap classes 得到了侧边栏和 ProjectMain 的小动画:
<div class="animated fadeInUp">
两个组件都完成了整个生命周期。
默认情况下,appOverview 在边栏中处于选中状态,CurentProjectAppOverview.vue 在 ProjectMain 中作为组件加载。
然后我单击侧边栏中的 appSettings,然后将 class 添加到侧边栏中的该项目以将其标记为已选中,并在 ProjectMain 中将 CurrentProjectSettings.vue 作为组件加载。
但是在面包屑中我有一个按钮可以转到“/myapps/newversion/:id”
这就是问题所在。当我点击转到“/myapps/newversion/:id”(router.push("/myapps/newversion/" + id);
)时,侧边栏上的第二个项目保持选中状态(appSettings)并且在 ProjectMain CurrentProjectSettings.vue 中保持加载状态,但我没有获取侧边栏和 ProjectMain 的 bootstrap 动画,组件不会经历它们的生命周期。
当我点击按钮转到“/myapps/newversion/:id”时,我想要的是我的 bootstrap 动画 (<div class="animated fadeInUp">
),我希望 Sidebar 和 ProjectMain经历他们的整个生命周期。我希望在侧边栏上选择默认项目(所以 appOverview),并在 ProjectMain 中加载默认组件(所以 CurentProjectAppOverview.vue)。
边栏中的每个项目都有彩色按钮。如果我从“/myapps/:id”转到“/myapps/newversion/:id”,我想从服务器加载数据到CurrentProjectAppOverview.vue,如果所有数据都已填满,我想要侧边栏为绿色,如果不是,则应为红色。
所以简而言之,当在这两条路线之间移动时,我希望能够加载数据并填写我想要的字段,我希望 bootstrap 动画和默认视图被选择和加载,他们应该去通过他们的整个生命周期。现在路由器只是按原样重用它们。
所以类似于“ReloadComponent: true”,或者销毁并重新创建组件。
我可以复制 SidebarProject.vue 和 ProjectMain.vue 并重命名它们,在每个路由中基本上加载一个副本,但这意味着我必须在不同的 .vue 文件中编写相同的代码。
之前有一个选项可以将 YouComponent.route.canReuse 设置为 false,我认为这会做我想要的,但它在最新版本中被删除了。
看起来你正在使用 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},
],
}
]
})
我有 "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>
所以,我所做的是告诉父模板查看路由器视图的命名视图。并根据路径,拉出我在路由器映射中指定的组件。
对于我的 '/' 路径工具栏 == 工具栏组件,但在 '/create' 路径工具栏 = eventToolbar 组件。
默认组件是动态的,这使我可以使用子组件而无需换出工具栏或替代组件。
这是我想出的:
import ProjectMain from './templates/ProjectMain.vue';
import SidebarProject from './templates/SidebarProject.vue';
//现在浅拷贝对象,因此新对象被视为单独的 .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 组件,但实际上它们是相同的。所以我得到了我想要的一切:组件的重新加载、动画、生命周期,而且我不必编写多个相似或相同的组件。
您怎么看,我只是不确定这是否是最佳做法。
部分感谢: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 更改但组件保持不变时,我只是再次调用该方法。这会处理新数据。
至于重新触发 bootstrap 动画,我使用 redraw();
功能,我在应用程序开始时添加到 jQuery。这会重新触发 URL 更改时的动画:
$("#breadcrumbsCurrentProject").find(".animated").removeClass("fadeIn").redraw().addClass("fadeIn");
我遇到了同样的问题。我将引用一个找到的答案,这真的很简单也很棒。
最简单的解决方案是将 :key 属性添加到 :
<router-view :key="$route.fullPath"></router-view>
这是因为如果同一组件被寻址,Vue Router 不会注意到任何变化。使用密钥,对路径的任何更改都会触发使用新数据重新加载组件。
我有几条路线,每条路线加载 3 个组件。其中两个组件在所有路线上都是相同的。 当我在这些路由之间移动时,我想传递新数据,并且在组件的某些初始化事件上,我想填充该组件的数据,以便它反映在 UI 上。 我还想重新触发正在加载的组件的 bootstrap 动画。 我将如何去做。 因为现在,我不知道在组件生命周期的哪个位置获取数据并使用这些新数据重新呈现组件。 具体来说,在 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;
}
});
如果我到达“/myapps/:id”。它加载了侧边栏和 ProjectMain,我用这个 bootstrap classes 得到了侧边栏和 ProjectMain 的小动画:
<div class="animated fadeInUp">
两个组件都完成了整个生命周期。
默认情况下,appOverview 在边栏中处于选中状态,CurentProjectAppOverview.vue 在 ProjectMain 中作为组件加载。 然后我单击侧边栏中的 appSettings,然后将 class 添加到侧边栏中的该项目以将其标记为已选中,并在 ProjectMain 中将 CurrentProjectSettings.vue 作为组件加载。
但是在面包屑中我有一个按钮可以转到“/myapps/newversion/:id”
这就是问题所在。当我点击转到“/myapps/newversion/:id”(router.push("/myapps/newversion/" + id);
)时,侧边栏上的第二个项目保持选中状态(appSettings)并且在 ProjectMain CurrentProjectSettings.vue 中保持加载状态,但我没有获取侧边栏和 ProjectMain 的 bootstrap 动画,组件不会经历它们的生命周期。
当我点击按钮转到“/myapps/newversion/:id”时,我想要的是我的 bootstrap 动画 (<div class="animated fadeInUp">
),我希望 Sidebar 和 ProjectMain经历他们的整个生命周期。我希望在侧边栏上选择默认项目(所以 appOverview),并在 ProjectMain 中加载默认组件(所以 CurentProjectAppOverview.vue)。
边栏中的每个项目都有彩色按钮。如果我从“/myapps/:id”转到“/myapps/newversion/:id”,我想从服务器加载数据到CurrentProjectAppOverview.vue,如果所有数据都已填满,我想要侧边栏为绿色,如果不是,则应为红色。
所以简而言之,当在这两条路线之间移动时,我希望能够加载数据并填写我想要的字段,我希望 bootstrap 动画和默认视图被选择和加载,他们应该去通过他们的整个生命周期。现在路由器只是按原样重用它们。
所以类似于“ReloadComponent: true”,或者销毁并重新创建组件。
我可以复制 SidebarProject.vue 和 ProjectMain.vue 并重命名它们,在每个路由中基本上加载一个副本,但这意味着我必须在不同的 .vue 文件中编写相同的代码。
之前有一个选项可以将 YouComponent.route.canReuse 设置为 false,我认为这会做我想要的,但它在最新版本中被删除了。
看起来你正在使用 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},
],
}
]
})
我有 "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>
所以,我所做的是告诉父模板查看路由器视图的命名视图。并根据路径,拉出我在路由器映射中指定的组件。
对于我的 '/' 路径工具栏 == 工具栏组件,但在 '/create' 路径工具栏 = eventToolbar 组件。
默认组件是动态的,这使我可以使用子组件而无需换出工具栏或替代组件。
这是我想出的:
import ProjectMain from './templates/ProjectMain.vue';
import SidebarProject from './templates/SidebarProject.vue';
//现在浅拷贝对象,因此新对象被视为单独的 .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 组件,但实际上它们是相同的。所以我得到了我想要的一切:组件的重新加载、动画、生命周期,而且我不必编写多个相似或相同的组件。 您怎么看,我只是不确定这是否是最佳做法。
部分感谢: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 更改但组件保持不变时,我只是再次调用该方法。这会处理新数据。
至于重新触发 bootstrap 动画,我使用 redraw();
功能,我在应用程序开始时添加到 jQuery。这会重新触发 URL 更改时的动画:
$("#breadcrumbsCurrentProject").find(".animated").removeClass("fadeIn").redraw().addClass("fadeIn");
我遇到了同样的问题。我将引用一个找到的答案,这真的很简单也很棒。 最简单的解决方案是将 :key 属性添加到 :
<router-view :key="$route.fullPath"></router-view>
这是因为如果同一组件被寻址,Vue Router 不会注意到任何变化。使用密钥,对路径的任何更改都会触发使用新数据重新加载组件。