今天會著重介紹觸發時機,可以在什麼情境下使用,不會講解詳細的語法。
這是大家最熟悉的函式,在 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
這篇文章寫的比較倉促,之後會再回頭好好整理一次
如果有什麼建議或使用經驗,歡迎留言跟我分享~