今天會著重介紹觸發時機,可以在什麼情境下使用,不會講解詳細的語法。
這是大家最熟悉的函式,在 Composition API 中,會裡面定義要暴露給模板的屬性跟方法。
setup()
是 Vue 元件生命週期中,第一個被呼叫的函式,在準備掛載元件前,會先執行 setup()
,過程中會建立元件實例,完成內部屬性、狀態初始化。
我們會在 setup 內去同步註冊 Lifecycle Hooks。
先定義完成 mounted
的意思,官方文件內的說明是:
簡單來說,假設根節點(通常是 App
)已經在 DOM 上,就是指元件和他的子元件都掛到 DOM tree 上,稱為完成 mount(ed),通常會翻譯成「掛載」或「渲染」。
什麼時候會更新?
通常是因為應響應式狀態改變,需要更新 DOM 內容。
先定義完成 unmounted
的意思,官方文件內的說明是:
setup()
期間初始化的 computed 和 watcher)簡單來說,假設根節點(通常是 App
)已經在 DOM 上,就是指元件和他的子元件都掛從 DOM tree 上移除,稱為完成 unmount(ed),通常會翻譯成「卸載」。
顧名思義,是用來守衛(guard)導航(Navigation),在每次導航前後呼叫,可以傳入非同步函式,並在內部使用await
,會等到執行完成,才會繼續跳轉。
每個 Guard 都可以接到 (to
, form
) 兩個參數,分別代表目標路由位置和當前路由位置,從 to
和 from
物件中,可以取得導向的 href
、hash
、query
、params
和 meta
等等,可以透過這些參數,去 fetch 需要的資料。(完整屬性參考)
Global Before Guards:router.beforeEach
Global Resolve Guards:router.beforeResolve
Global After Hooks:router.afterEach
Per-Route Guard:beforeEnter
router.routes
params
、query
或 hash
改變時不會觸發In-Component Guards(Composition API)
可以用在由 <router-view>
渲染的元件 setup()
內。
onBeforeRouteUpdate
:在路由更新前onBeforeRouteLeave
:在離開路由之前用類似 Vue 專案剛建立時的架構來看 Lifecycle Hook 和 Router Guard 被呼叫的順序。
進入網站後
/Home
路由 - beforeEnter在載入路由頁面元件(View)時,會先呼叫 route guard 確定導向,才會開始跑 <router-view>
內元件的生命週期。
從 /
切換到 /Rooms
/Rooms
路由 - beforeEnterwatchEffect
不是生命週期的 Hook,但也很適合用在這種情境上使用方式可以參考 - Day 21: 來發 API 吧!Async Composition API setup()
有了 Route Guard,我們就可以在頁面(元件)載入之前,提前送出請求,避免等待資料的空白時間,也就不需要特別處理元件的 loading 狀態!
Vue Router 有 3 個 route guard 符合這個需求。
針對整個 url 的改變 | 針對 Route 個別設定 |
---|---|
beforeEach、 beforeResolve | beforeEnter |
如果是針對整個網站的網址,在觸發導向時都要發 API,就適合使用 beforeEach
和 beforeResolve
,舉例來說:要確認使用者是否登入,或是身份權限是否足夠,才能讓使用者看到網站畫面,就可以用這兩個 guard。
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
else next()
})
如果是在特定的 route
頁面/元件,才需要發 API,就適合使用 beforeEnter
,還可以透過帶 url 參數,去 get 特定的資料。
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: "/",
name: "home",
component: HomeView,
},
{
path: "/rooms",
name: "rooms",
component: () => import("../views/RoomsView.vue"),
//進入 /rooms 前,先去 GET 全部房間資訊
beforeEnter: async (to) => {
//可是 route.js 內沒有 rooms 這個變數
//這個方法建議配合狀態管理器使用
rooms.value = await hotelAPI.GET("/room", to.params.id);
},
},
{
path: "/room/:id",
name: "room",
component: () => import("../views/RoomView.vue"),
//可以透過 URL 參數,先去 GET 指定房間資訊
beforeEnter: async (to) => {
const id = parseInt(to.params.id);
//可是 route.js 內沒有 roomInfo 這個變數
//這個方法建議配合狀態管理器使用
roomInfo.value = await hotelAPI.GET("/room", to.params.id);
},
},
],
});
註:當然也可以在 beforeEach guard 偵測這件事,那需要多寫 if (to.path === "/rooms")
,當需要提前拿資料的 route 越來越多, beforeEach guard 內的邏輯就會變得更複雜。
這時候會遇到一個問題,route.js
內沒有辦法取到元件的變數,元件也不能直接取到 route.js
裡拿到的 room
,這時候就可以搭配狀態管理器(例如:Pinia 和 Vuex),透過狀態管理器,可以將共用狀態抽出來,方便元件之間共用,要取用或更新共用狀態時,就可以直接從狀態管理器的 store 裡面拿,這也是狀態管理器的好用之處。
沒用過狀態管理器的人,可能會覺得陌生詞彙很多,等到「狀態管理器」的章節會再提到。
在同個路由下做參數切換時,可以在該路由頁面/元件的 setup 內註冊 onBeforeRouteUpdate guard,每次參數切換時,自動從遠端拿到新資料。
舉例來說:url 從 /room/${id1}
到 /room/${id2}
實際情境說明:
//inside <script setup>
import { onBeforeRouteUpdate } from "vue-router";
import { ref } from "vue";
const room = ref();
onBeforeRouteUpdate(async (to, from) => {
if (to.params.id !== from.params.id) {
room.value = await hotelAPI.GET("/room", to.params.id);
}
});
注意上面這個範例,只有從 /room/${id1}
到 /room/${id2}
會觸發 onBeforeRouteUpdate,從 /rooms
到 /room/${id1}
並不會觸發 guard。
連假是鐵人賽殺手吧QQ
這篇文章寫的比較倉促,之後會再回頭好好整理一次
如果有什麼建議或使用經驗,歡迎留言跟我分享~