🔥【Vue.js → Nuxt 入門推薦!🌟 新書即將上市 🌟】
📘《想要 SSR 嗎?就使用 Nuxt 吧!Nuxt 讓 Vue.js 更好處理 SEO 搜尋引擎最佳化》
👀 Nuxt v4 內容與範例也可以參考並購買本系列文筆著所著書籍
📦 預計於:2025/08/14 出版,目前天瓏書局預購有 7️⃣8️⃣ 折優惠
👉 點此前往購買:https://pse.is/7yulm5
注意:Nuxt 4 已於 2025/07/16 釋出,本文部分內容或範例可能和最新版本有所不同
前一篇,我們完成了新增文章的頁面與流程,在網站開發的過程中,有些頁面是具有瀏覽的限制,例如,我們不希望一般的使用者能進到管理者頁面專用的頁面進行操作,這時候我們就需要做一些權限的驗證與限制,在 Nuxt 的頁面提供了路由中間件可以在我們導航至頁面之前,執行一些處理函數,就實作導航守衛 (Navigations Guards) 的效果。最後會介紹一下在 Nuxt 3 所提供的頁面和布局切換時的進度條 (Progress bar) 與轉場效果 (Transitions)。
首先,我們新增一個路由中間件 ./middleware/manage-auth.js 內容如下:
import { useUserStore } from '@/stores/user'
export default defineNuxtRouteMiddleware(() => {
  if (process.client) {
    const userStore = useUserStore()
    if (!userStore.profile?.id) {
      return navigateTo('/login')
    }
  } else {
    return navigateTo('/')
  }
})
在頁面元件中使用 definePageMeta() 來套用 manage-auth 中間件。調整 ./pages/manage/articles/create.vue 內容:
<script setup>
// ...
definePageMeta({
  middleware: 'manage-auth'
})
</script>
我們首頁新增一個可以導向至 /manage/articles/create 頁面的按鈕。
<NuxtLink
  class="text-md mt-12 rounded-sm bg-emerald-500 py-2 px-4 font-medium text-white hover:bg-emerald-600 focus:outline-none focus:ring-2 focus:ring-emerald-400 focus:ring-offset-2"
  to="/manage/articles/create"
>
  前往撰寫文章
</NuxtLink>
當我們處於未登入的情況,點擊前往後,會經由中間件判斷 process.client 是否是在客戶端,進而從 User Store 取出使用者資訊進行判斷,當不存在 userStore.profile.id 時,表示未登入我們將導航至登入頁面 /login;當登入完成後,就可以使用按鈕成功導航至新增文章的頁面。如果process.client 為 false,表示導航是在伺服器端觸發的,例如,我們直接透過網址進入新增文章頁面,將會一律被重新導航至首頁。
當使用者在瀏覽網站時被引導或準備登入時,我們可以將使用者目前的頁面進行記錄,以便登入完成後,可以重新導向至使用者登入前的頁面,以此提供使用者更棒的體驗。
首先,我們新增一個路由中間件 ./middleware/logged-in-redirect.js 內容如下:
export default defineNuxtRouteMiddleware((to, from) => {
  if (from && to.path !== from.path && !to.query.redirect_to) {
    let redirectTo = null
    if (from.query.redirect_to) {
      redirectTo = from.query.redirect_to
      from.query.redirect_to = undefined
    } else {
      redirectTo = from.fullPath
    }
    to.query.redirect_to = redirectTo
    return navigateTo(to)
  }
})
這個 logged-in-redirect 中間件的處理邏輯,我們接收 to 與 from,分別為目標頁面與來源頁面,當使用者目標頁面 /login 還未帶上了 Query 參數 redirect_to,我們就將來源的完整路徑添加上去 from.fullPath,最後進行導向。
這裡需要進行判斷
redirect_to,否則會重複發生重新導向。
在登入頁面中使用 definePageMeta() 來套用 logged-in-redirect 中間件。調整 ./pages/login.vue 內容:
<script setup>
// ...
definePageMeta({
  middleware: 'logged-in-redirect'
})
</script>
在登入完成的地方,我們就可以使用 navigateTo() 導向至 redirect_to 給的頁面路徑。
<script setup>
const route = useRoute()
const handleEmailLogin = async () => {
  // ...
  navigateTo(route.query.redirect_to ?? '/')
}
</script>
完成後,我們從首頁點擊登入後.當登入完成後就會導向回首頁;而從文章頁面點擊登入,完成後則會導向回文章頁面。
Nuxt 3 提供一個 <NuxtLoadingIndicator> 元件,用作頁面導航後顯示載入的進度,會在頁面上方有一個進度條 (Progress bar)。
只需要將 <NuxtLoadingIndicator> 元件添加至 app.vue 或布局之中,調整 app.vue 內容如下:
<template>
  <NuxtLayout>
    <NuxtLoadingIndicator />
    <NuxtPage />
  </NuxtLayout>
</template>
元件可以傳入的屬性 (Props) 如下:
色碼或repeating-linear-gradient() 函数,預設為 repeating-linear-gradient(to right,#00dc82 0%,#34cdfe 50%,#0047e1 100%)。px,預設值為 3。毫秒,預設值為2000。毫秒,預設值為200。當我們從首頁切換頁面時,網頁上方就會出現一個進度條,表示頁面正在載入中。
除了載入的進度條,頁面切換之間,也可以使用轉場效果 (Transitions) 來讓頁面之間的銜接更柔順,Nuxt 利用了 Vue 內建的 <Transition> 元件來幫助處理轉場和動畫,用以響應不斷變化的頁面與狀態。
Nuxt 預設為所有頁面 (Pages) 都設置了轉場,如果要啟用,請將以下 CSS 添加至 app.vue 中。
<template>
  <NuxtPage />
</template>
<style>
.page-enter-active,
.page-leave-active {
  transition: all 0.4s;
}
.page-enter-from,
.page-leave-to {
  opacity: 0;
  filter: blur(1rem);
}
</style>
每個頁面的 pageTransition 預設屬性皆為 { name: 'page', mode: 'out-in' },name 為 page 也就對應了 CSS 類別的開頭;mode 有 in-out, out-in 及 default三種參數可選。
.[pageTransition.name]-enter-active,
.[pageTransition.name]-leave-active {
  transition: all 0.4s;
}
.[pageTransition.name]-enter-from,
.[pageTransition.name]-leave-to {
  opacity: 0;
  filter: blur(1rem);
}
套用好頁面的轉場,就會有切換頁面時有模糊的效果。
既然知道 pageTransition 的 name 會對應頁面轉場的 CSS 名稱,我們就可以來自定義更多轉場,讓不同頁面套用不同的效果。
例如在 app.vue 添加 rotate 為前綴的類別名稱 CSS。
<style>
/* ... */
.rotate-enter-active,
.rotate-leave-active {
  transition: all 0.4s;
}
.rotate-enter-from,
.rotate-leave-to {
  opacity: 0;
  transform: rotate3d(1, 1, 1, 15deg);
}
</style>
在頁面中使用 definePageMeta() 來設定 pageTransition.name 為 rotate。調整 ./pages/login.vue 添加如下程式碼。
<script setup>
// ...
definePageMeta({
  pageTransition: {
    name: 'rotate'
  }
})
</script>
當頁面切換時,皆會使用預設的模糊轉場效果,當切換至登入頁面就會套用指定的 rotate 頁面轉場,而有旋轉的轉場效果。
Nuxt 同樣為所有布局 (Layouts) 都設置了轉場,如果要啟用,請將以下 CSS 添加至 app.vue 中。
.layout-enter-active,
.layout-leave-active {
  transition: all 0.4s;
}
.layout-enter-from,
.layout-leave-to {
  filter: grayscale(1);
}
建立 ./layouts/teal.vue 布局,程式碼如下:
<template>
  <div class="h-screen bg-teal-50">
    <slot />
  </div>
</template>
將登入頁面的布局套用 teal。
<script setup>
// ...
definePageMeta({
  layout: 'teal'
})
</script>
建立 ./layouts/green.vue 布局,程式碼如下:
<template>
  <div class="h-screen bg-teal-50">
    <slot />
  </div>
</template>
將註冊頁面的布局套用 green。
<script setup>
// ...
definePageMeta({
  layout: 'green'
})
</script>
在登入頁面與註冊頁面切換時,因為兩個頁面使用了不同的布局,布局的轉場效果,使背影顏色會有灰階效果的轉場。
你也可以像自訂頁面轉場一樣,來使用 definePageMeta() 設定 layoutTransition.name 屬性,來指定自訂的轉場效果。
<script setup>
definePageMeta({
  layout: 'green',
  layoutTransition: {
    name: 'slide-in'
  }
})
</script>
頁面與布局的轉場效果,都可以透過 definePageMeta 來設定 pageTransition 或 layoutTransition 為 false 來禁止套用轉場效果。
<script setup>
definePageMeta({
  pageTransition: false
  layoutTransition: false
})
</script>
你也可以在 nuxt.config.ts 設置預設的頁面與轉場效果,例如:
export default defineNuxtConfig({
  pageTransition: {
    name: 'fade',
    mode: 'out-in' // default
  },
  layoutTransition: {
    name: 'slide',
    mode: 'out-in' // default
  }  
})
當然要將所有頁面與布局預設禁用也可以設置如下:
export default defineNuxtConfig({
  pageTransition: false,
  layoutTransition: false
})
pageTransition 與 layoutTransition 接受的屬性可以參考 TransitionProps。
transition在 app.vue 中使用 <NuxtPage /> 時,你可以將 TransitionProps 作為元件的 Props 來啟用全域預設的轉場效果。
<template>
  <div>
      <NuxtPage :transition="{
        name: 'bounce',
        mode: 'out-in'
      }" />
    </NuxtLayout>
  </div>
</template>
當使用此方法設定轉場效果時,就不能在頁面中使用
definePageMeta()來覆蓋這裡的頁面轉場設置。
這篇我們主要實作了導航守衛,來為特定頁面添加瀏覽的權限,我們除了使用客戶端的 User Store 驗證外,也可以搭配 Cookie 再後端進行驗證,甚至為每個請求解析使用者,並查詢資料庫是否具有權限瀏覽,以此來控制使用者瀏覽頁面的權限,除了前端的阻擋外,更重要的是後端 API 也需要搭配進行權限驗證,才能有要的防止網頁漏洞產生,否則可能會發生,使用者無權瀏覽新增或管理的頁面,但是可以透過打 API 來進行相關操作,這樣是非常危險的。最後,我們將頁面切換時設置了進度條與轉場效果,使得整體網站能提供使用者更好的操作體驗,更多的轉場設置,也可以參考官方文件。
感謝大家的閱讀,這是我第一次參加 iThome 鐵人賽,請鞭小力一些,也歡迎大家給予建議 :)
如果對這個 Nuxt 3 系列感興趣,可以訂閱接收通知,也歡迎分享給喜歡或正在學習 Nuxt 3 的夥伴。