嗨!今天要跟大家分享的是如何在 Nuxt 3 專案中運用 Pinia 這個強大的狀態管理工具,並且實作一個客製化的 Loading 元件。無論你是剛接觸 Vue 生態系的新手,還是想要更新技能的資深開發者,這篇文章都會帶給你滿滿的收穫!
我們會從最基礎的 Pinia 介紹開始,一步步帶你實作到最後的成品。準備好你的開發環境,讓我們一起來深入探索 Nuxt 3 和 Pinia 的奧妙吧!
房東不給養鸚鵡 - 那就用 Nuxt + Express + MongoDB 30 天寫一個全端鸚鵡專案。
挑戰人生第一次鐵人賽,就來個佛心分享 side project,從專案發想、規劃、設計、資料庫、開發到部署,技術使用 Nuxt 3、Tailwind CSS、Pinia、Axios、Express、MongoDB,製作一個前後端分離的鸚鵡專案,功能主要介紹食物計算機和聯絡我們,希望可以讓更多人瞭解專案的完整流程 ✨
IT 全文章連結Pinia 簡介
Pinia 是 Vue 生態系統中的新一代狀態管理庫。它提供了一種簡單、直觀的方式來管理應用程序的狀態。Pinia 的主要特點包括:
- 輕量級:比 Vuex 更小、更快。
- 類型安全:完全支援 TypeScript。
- 開發者工具支援:可以輕鬆追蹤狀態變化。
- 模塊化設計:無需創建複雜的模塊樹。
- 無需額外的樣板代碼:使用簡單的 API 設計。
現在,讓我們一起來看看如何在 Nuxt 3 專案中使用 Pinia 吧!
在 Nuxt 3 中使用 Pinia 的步驟
1. 安裝 Pinia
首先,我們要在專案目錄中執行以下指令:
1 | npm install pinia @pinia/nuxt |
💡 小提醒:如果你跟我一樣遇到安裝問題,別擔心!試試看到
package.json
檔案中,將"vue": "latest"
改成"vue": "^3.4.0"
,這個小撇步通常能解決問題喔!
1 | "dependencies": { |
2. 配置 Pinia
接下來,我們要在 nuxt.config.ts
中把 Pinia 加進去:
1 | export default defineNuxtConfig({ |
這個設定就像是在告訴 Nuxt:「欸,我要用 Pinia 喔!」這樣 Nuxt 就會幫我們把 Pinia 整合到專案中,讓我們可以盡情使用它的所有功能。
3. 創建 Store
現在,讓我們來創建一個 store 吧!我們要在 stores
目錄下創建一個 api.ts
檔案。
1 | // stores/api.ts |
讓我們來解釋一下這段程式碼:
- defineStore: 這是 Pinia 提供的函數,用來創建一個 store。你可以把 store 想像成一個專門儲存和管理某些特定資料的地方。
- axios: 這是一個非常受歡迎的 JavaScript 庫,用來發送 HTTP 請求。簡單來說,它就是幫我們跟伺服器溝通的工具。
- baseURL: 這是我們 API 的基本網址。設定好這個之後,我們後續發送請求時就不需要每次都寫完整的網址了。
- actions: 在 Pinia 中,actions 是用來定義可以改變 store 狀態的方法。這裡我們定義了一個
fetchFoodList
方法,用來從伺服器獲取食物列表。 - async/await: 這兩個關鍵字用於處理非同步操作。你可以把它想像成:「這個操作可能需要一點時間,但不用擔心,我會等它完成的!」
4. 在元件中使用
最後,讓我們來看看如何在元件中使用我們剛剛創建的 store。我們將在 pages/calculator.vue
中使用它:
1 | <script setup> |
讓我們來解釋一下這個元件:
- useApiStore: 這是我們用來獲取 store 實例的函數。通過調用它,我們就可以使用 store 中定義的所有方法和資料。
- ref: 這是 Vue 3 中用來創建響應式變數的函數。當
foodList
的值改變時,Vue 會自動更新相關的畫面。 - async function: 這表示
fetchFoods
是一個非同步函數。它可能需要一些時間來完成,但不會阻塞其他程式碼的執行。 - try/catch: 這是用來處理錯誤的結構。如果在
try
區塊中的程式碼出錯,就會執行catch
區塊中的程式碼。 - onMounted: 這是一個生命週期鉤子,它會在元件被掛載到頁面上後立即執行。我們用它來確保一旦頁面準備好,就立即獲取食物列表。
- template: 這部分定義了元件的 HTML 結構。
{{ foodList }}
會將foodList
的內容直接顯示在頁面上。
通過這種方式,我們實現了一個簡單但功能完整的食品列表頁面。當頁面載入時,它會自動從伺服器獲取食品資料,並將其顯示出來。如果獲取過程中出現任何錯誤,我們也會在控制台中看到相關信息,方便進行除錯。
目前頁面截圖
畫面上印出的就是我們取回來的食物資料
在 Nuxt 3 中添加自定義 Loading 元件的步驟指南
1. 準備 Loading 動畫
前往 Lottie 網站 尋找喜歡的 GIF 動畫。
下載選中的 GIF 檔案。
這是流程示範,可以選自己喜歡的下載,我也不是下載這個動畫 XD
注意免費的有下載數量限制!將下載的 GIF 檔案放入
assets/images/
資料夾 (我的 GIF 檔案命名為birdGif.gif
)
2. 設置事件總線 (stores/eventBus.ts)
創建 stores/eventBus.ts
檔案:
1 | // stores/eventBus.ts |
詳細解釋:
export const isLoading = ref(false)
:- 這裡使用 Vue 3 的
ref
函數創建了一個響應式變數。 - 初始值設為
false
,表示一開始不顯示 loading。 - 使用
export
使得這個變數可以在其他文件中被引入和使用。
- 這裡使用 Vue 3 的
export function showLoading()
和export function hideLoading()
:- 這兩個函數用於控制
isLoading
的值。 showLoading()
將isLoading
設為true
,表示開始載入。hideLoading()
將isLoading
設為false
,表示載入結束。- 這種設計讓我們可以在應用的任何地方輕鬆控制 loading 狀態。
補充說明:事件總線(Event Bus)是一種常見的設計模式,用於在不同元件間進行通訊。在這裡,我們用它來管理全局的 Loading 狀態。這種方法特別適合處理跨元件的狀態,比如 Loading 狀態這種需要在整個應用中共享的資訊。
- 這兩個函數用於控制
3. 創建 Loading 元件 (components/LoadingTool.vue)
創建 components/LoadingTool.vue
檔案:
1 | <script setup lang="ts"> |
詳細解釋:
<script setup lang="ts">
:- 這是 Vue 3 的組合式 API 寫法,
setup
表示這個腳本區塊會在組件創建時自動執行。 lang="ts"
表示使用 TypeScript。
- 這是 Vue 3 的組合式 API 寫法,
import { isLoading } from '~/stores/eventBus'
:- 從事件總線中引入
isLoading
變數,使得這個組件可以根據全局狀態來顯示或隱藏。
- 從事件總線中引入
<template>
部分:v-if="isLoading"
: 這是一個 Vue 指令,當isLoading
為 true 時,才會顯示這個 div。<img src="~/assets/images/birdGif.gif" alt="birdGif" />
: 顯示 loading 動畫。
<style scoped>
:scoped
表示這些樣式只應用於這個組件。.spinner-container
的樣式設置:@apply bg-bg bg-opacity-70;
: 這是 Tailwind CSS 的語法,設置背景和透明度。position: fixed; inset: 0;
: 使 loading 覆蓋整個螢幕。z-index: 1300;
: 確保 loading 顯示在其他元素之上。display: flex; justify-content: center; align-items: center;
: 使 loading 動畫居中顯示。
補充說明:Vue 3 的組合式 API(Composition API)是一種新的程式碼組織方式,它讓我們能更靈活地組織和重用程式碼。
<script setup>
是其中一個語法糖,它簡化了組合式 API 的使用方式。使用<script setup>
讓我們的程式碼更簡潔,同時保持了強大的功能性。
4. 在主應用元件中使用 Loading 元件 (app.vue)
修改 app.vue
檔案:
1 | <template> |
詳細解釋:
- 這是 Nuxt 3 的主應用組件,它包裝了整個應用。
<Header />
: 這是導航欄組件,放在頁面頂部。<NuxtPage />
: 這是 Nuxt 3 的特殊組件,用於顯示當前路由對應的頁面內容。<LoadingTool />
: 這裡引入了我們剛才創建的 Loading 組件。- 將它放在這裡意味著 Loading 效果可以覆蓋整個應用,在任何頁面都能顯示。
5. 在頁面中使用 Loading 效果 (pages/calculator.vue)
修改 pages/calculator.vue
檔案:
1 | <script setup> |
詳細解釋:
- 引入
showLoading
和hideLoading
: 用於控制 loading 狀態的函數。 async function fetchFoods()
:- 這是一個非同步函數,用於獲取食品列表數據。
showLoading()
: 在開始獲取數據前顯示 loading。await apiStore.fetchFoodList()
: 調用 API 獲取數據。- 如果成功獲取數據,將其存儲在
foodList
中。 hideLoading()
: 在finally
區塊中調用,確保無論成功與否都會隱藏 loading。補充說明:非同步函數(Async Function)和
try-catch-finally
結構是處理非同步操作的重要工具。非同步函數允許我們以同步的寫法處理非同步操作,大大提高了程式碼的可讀性。而try-catch-finally
結構則幫助我們優雅地處理可能發生的錯誤,確保無論操作成功與否,都能執行必要的清理工作(在這裡是隱藏 Loading)。
這種設計允許我們在數據加載過程中顯示 loading 效果,提升用戶體驗。同時,由於 loading 狀態是全局管理的,我們可以在應用的任何部分輕鬆地控制它的顯示和隱藏。
結語
哇!恭喜你完成了這趟 Nuxt 3 和 Pinia 的學習之旅!我們不僅學會了如何使用 Pinia 進行狀態管理,還成功實作了一個超酷的自定義 Loading 元件。這些技能絕對會讓你的前端開發功力大幅提升!
記住,程式開發就像是在玩樂高積木,我們今天學到的每個概念都是一塊重要的積木。Pinia 是管理狀態的積木,自定義 Loading 元件則是提升使用者體驗的積木。隨著你不斷學習和實踐,你會發現自己能夠搭建出越來越複雜、越來越酷炫的應用程式。
最後,別忘了實際動手做做看!理論學習很重要,但真正的進步來自於實踐。嘗試在自己的專案中運用這些技巧,你會發現更多有趣的應用方式。
繼續保持學習的熱情,相信不久的將來,你一定會成為一位出色的前端工程師!加油!
大家有沒有想要更詳細補充的部分呢?歡迎在下方留言分享喔!讓我們一起在 Nuxt3 的世界中探險吧!加油!
希望這篇文章有幫助到你,謝謝你的觀看,若有想看的系列也歡迎告訴我 😉