0%

Vue 筆記 - 路由守衛 BeforeRouteEnter 跟 BeforeRouteLeave 實作

簡介

屬於單一元件 component 的 Hooks,分別有以下三種:

  • beforeRouteEnter 進入路由之前
  • beforeRouteUpdate 更新路由之前
  • beforeRouteLeave 離開路由之前

使用方法

起手式如下,並依照情境需求使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<template> ... </template>

<script>
export default {
data(){
return {
...
}
},
beforeRouteEnter(to, from) {
...
},
beforeRouteUpdate(to, from) {
...
next();
},
beforeRouteLeave (to, from) {
// ...
}
};
</script>

beforeRouteEnter 進入路由之前

提供 to ,from, next 三個參數使用。

在路由尚未進入該元件時被調用,須注意在這個方法裡面因為還沒有建立物件實體,故無法取得 this,但可以在 next 參數中取得元件實體。

1
2
3
4
5
6
7
beforeRouteEnter(to, from, next){
//從 next 取得物件實體

next(vm =>{
// 這邊可以取得物件實體
})
}

透過開發人員工具可以看到印出的結果,

to

to

from

from

tofrom 都可以看到 fullpath 對應的路徑,以及相關的資訊,像是 matched 就會看到上下頁的內容:

next

next

實際情境優化

此是實際情境,我有一頁會員註冊頁要填入姓名的 member-name 頁面,原本的寫法是只要進入此頁就把填寫過的資料清空,但使用情境上其實不友善,因為變成使用者按上一頁的功能鍵時,原本在這頁填寫的內容都被清空,故修改成當我重新進入此頁時,只要路由是從 member-name 來的話,就記錄在 store 裡。

1
2
3
4
5
6
7
8
9
// 如果 path 是 member-name 頁面要保留資料,其他頁面都要清空資料
beforeRouteEnter(to, from, next) {
const resultPath = from.name.split('___')[0];
next((vm) => {
if (resultPath !== 'member-name') {
vm.$store.commit(`Member/${mutations.MEMBER_RESET_NEWMEMBERDATA}`);
}
});
},

beforeRouteUpdate 更新路由之前

實際上使用是當路由被改變,但使用的元件是同一個時使用。由於只是更新元件內容,但元件本身沒有被銷毀,此時就會觸發 beforeRouteUpdate Hook,方法內的參數與 beforeRouteEnter 大致相同,只是沒有 next() 可以用,但因為元件沒有被銷毀,所以已經可以取得物件實體,可以使用 this,也因為已經有 this 可以使用了,所以也不需要使用 next

1
2
3
4
beforeRouteUpdate (to, from) {
// just use `this`
this.name = to.params.name
}

(這個我實務上還沒遇到過,若有實戰情境會再回頭補上範例)。

beforeRouteLeave 離開路由之前

是在離開此元件時會自動調用此 Hook,也是提供 to, from 兩個參數可以使用,大部分使用情境是詢問使用者是否再跳轉到其他路由前使用。

1
2
3
4
beforeRouteLeave (to, from) {
const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
if (!answer) return false
}

可以使用 next 為選填參數,但要注意的是若指定路由卻沒有做判斷,則會陷入無限循環,例:

1
2
3
4
beforeRouteLeave(to, from, next){
// ...離開路由條件
next('/home')
}

原因是遇到 next(‘/home’) 會中斷當前路由導航,然後會離開此頁面,回到 home 頁面,但因為路由參數 to.path 會一直去導到 home 頁面,導致產生無限循環,所以如果只要前往下一頁,但不指定,就要加上判斷,並且不指定頁面,改寫上方範例後如下:

1
2
3
4
5
6
7
8
beforeRouteLeave(to, from, next){
if(to.fullPath === '/home'){
next()
}else{
next('/home')
}

}

這樣就不會進入無限循環了。

實際情境實作

因從 member-name 頁面回到此頁時,除了填寫資料被清空外,勾選過的選項也沒有被記錄,使用者如果只是想回到這頁修改資料的話,變成要重新勾選,故改成當我離開此元件時,先把勾選過的選項紀錄,並且跳轉到下一個路由。

1
2
3
4
5
6
7
8
9
// 使用 beforeRouteLeave 方法,從 member-name 頁面回到此頁時,保留填寫過的同意條款與年齡的 checkbox 選項。
beforeRouteLeave(to, from, next) {
this.$store.commit(
`Member/${mutations.MEMBER_SELECTED_TERMS_AND_CONDITIONS}`,
this.termsAndConditions,
);
this.$store.commit(`Member/${mutations.MEMBER_SELECTED_AGE}`, this.age);
next();
},

關於 next 參數

  • next(): 不指定路由,直接跳到下一頁。
  • next(false): 中斷當前導航,若瀏覽器 URL 改變,URL 路徑會重置到 from 路由對應的路徑。
  • next('/') 或是 next({path: '/'}): 跳轉到不同的路徑,當前導航會被中斷,然後跳轉到一個新的路由。
  • next(error): 該路由會被終止並且把錯誤傳給 route.onError() 來使用。

Demo

持續更新中~~
https://github.com/hsuchihting/vue_router_demo/tree/master/vue-tailwindcss

參考資料