[英]Vue-router reload components
我有幾條路線,每條路線加載 3 個組件。 其中兩個組件在所有路線上都是相同的。 當我在這些路由之間移動時,我想傳遞新數據,並在組件的某些初始化事件上填充該組件的數據,以便它反映在 UI 上。 我還想重新觸發正在加載的組件的引導動畫。 我 go 如何做到這一點。 因為現在,我不知道在組件生命周期的哪個位置獲取數據並使用這些新數據重新呈現組件。 具體來說,在 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>
當我單擊 Sidebar 上的某個項目時,我會向 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,我得到了一些 animation 的側邊欄和帶有這個引導類的 ProjectMain: <div class="animated fadeInUp">
並且這兩個組件都經歷了整個生命周期。
默認情況下,側邊欄中的 appOverview 處於選中狀態,CurentProjectAppOverview.vue 作為 ProjectMain 中的組件加載。 然后我點擊邊欄中的 appSettings,class 被添加到邊欄中的該項目以將其標記為已選中,並在 ProjectMain 中將 CurrentProjectSettings.vue 作為組件加載。
但是然后在面包屑中我有一個按鈕到 go 到“/myapps/newversion/:id” 這就是問題所在。 當我點擊 go 到“/myapps/newversion/:id”( router.push("/myapps/newversion/" + id);
)側邊欄上的第二個項目保持選中狀態(appSettings)並且在 ProjectMain CurrentProjectSettings.vue 保持已加載,但我沒有獲得側邊欄和 ProjectMain 的引導程序 animation,並且組件在其生命周期中沒有 go。
當我點擊按鈕 go 到“/myapps/newversion/:id”時,我想要的是我的引導程序 animation ( <div class="animated fadeInUp">
),我希望 Sidebar 和 ProjectMain 在整個生命周期內都為 go。 我希望在側邊欄上選擇默認項(因此是 appOverview),並在 ProjectMain 中加載默認組件(因此是 CurentProjectAppOverview.vue)。
邊欄中的每個項目都有彩色按鈕。 如果我 go 從“/myapps/:id”到“/myapps/newversion/:id”,我想將數據從服務器加載到 CurrentProjectAppOverview.vue,如果所有數據都已填充,我希望側邊欄上的按鈕是綠色,如果不是,則應為紅色。
所以簡而言之,當在這兩條路線之間移動時,我希望能夠加載數據並填寫我想要的字段,我希望引導 animation 和默認視圖被選擇和加載,它們應該 go 通過他們的整個生命周期。 現在路由器只是按原樣重用它們。
所以像“ReloadComponent:true”之類的東西,或者銷毀並重新創建組件。
我可以復制 SidebarProject.vue 和 ProjectMain.vue 並重命名它們,並且在每個路由中基本上加載一個副本,但這意味着我必須在不同的 .vue 文件中編寫相同的代碼。
之前有一個選項可以將 YouComponent.route.canReuse 設置為 false,我認為這會做我想做的,但它在最新版本中被刪除了。
我遇到了同樣的問題。 我將引用一個找到的答案,這非常簡單而且很棒。 最簡單的解決方案是將:key屬性添加到:
<router-view :key="$route.fullPath"></router-view>
這是因為如果正在尋址相同的組件,Vue Router不會注意到任何變化。 使用密鑰,對路徑的任何更改都將觸發使用新數據重新加載組件。
部分地對此: 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");
看起來你正在使用vue-router。
我沒有你的代碼,但我可以告訴你我是如何處理的。 請參閱命名視圖 。
這是我的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組件。
這就是我提出的:
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組件,但它們實際上是相同的。 所以我得到了我想要的一切:重新加載組件,動畫,生命周期,而且我不必編寫多個相似或相同的組件。 您怎么看?我不確定這是否是最佳做法。
您可以通過添加:key="$route.fullPath"來強制重新加載組件。
對於子組件:
<Child :key="$route.fullPath" />
對於路由器視圖標簽:
<router-view :key="$route.fullPath" />
但是, :key="$route.fullPath"只能強制重新加載不同路由的組件,而不能強制重新加載同一路由的組件。 為了能夠強制重新加載同一路由的組件,我們需要向:key=添加一個值並更改該值。
*我們可以將Array分配給:key= 。
<template>
<Child
:key="[$route.fullPath, value]" // Can assign "Array" to ":key="
@childReload="reload" // Call @click="$emit('childReload')" in
/> // Child Component to increment the value.
</template>
OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR
<template>
<router-view
:key="[$route.fullPath, value]" // Can assign "Array" to ":key="
@routerViewReload="reload" // Call @click="$emit('routerViewReload')"
/> // in Child Component to increment the value.
</template>
<script>
export default {
name: "Parent", components: { Child, },
data() {
return {
value: 0,
};
},
methods: {
reload() {
this.value++;
}
}
}
</script>
但是,為了繼續同時使用$route.fullPath和value有時會導致一些錯誤,因此只有在發生諸如Click 之類的事件時,我們才同時使用$route.fullPath和value 。 除了像Click這樣的事件發生時,我們總是只需要使用$route.fullPath 。
<template>
<Child
:key="state ? $route.fullPath : [$route.fullPath, value]"
@childReload="reload" // Call @click="$emit('childReload')" in
/> // Child Component to increment the value.
</template>
OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR OR
<template>
<router-view
:key="state ? $route.fullPath : [$route.fullPath, value]"
@routerViewReload="reload" // Call @click="$emit('routerViewReload')" in
/> // Child Component to increment the value.
</template>
<script>
export default {
name: "Parent", components: { Child, },
data() {
return {
state: true,
value: 0,
};
},
methods: {
reload() {
this.state = false;
this.value++;
this.$nextTick(() => this.state = true);
}
}
}
</script>
不幸的是,在 Vue 中沒有簡單的方法可以正確地強制重新加載組件。 這是 Vue 目前的大問題。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.