🔥【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 釋出,本文部分內容或範例可能和最新版本有所不同
組合式函式 (Composables) 是一種利用 Vue 3 的 Composition API 來封裝和複用有狀態邏輯的函式,在 Nuxt 我們可以將一些通用的商業邏輯放置在 composables 來建立組合式函式,這樣一來就可以在各個頁面共用這個組合式函式。
下列這段是 Vue 依據 Options API 撰寫出來的程式碼,也是 Vue 2 處理邏輯的寫法,所謂 Options (選項、可選的) 指的就是以程式碼的性質來分割程式碼,所有設定資料初始值的都會在 data 這邊處理,這個元件所需要的方法則會在 methods 這裡建立,data 及 methods 也就是使用者需要的選項。
<script>
export default {
  data() {
    return {
      count: 0,
      doubleCount: 0
    }
  },
  methods: {
    increment() {
      this.count += 1
    },
    incrementByTwo() {
      this.doubleCount += 2
    }
  }
}
</script>
目前在 Vue 3 你仍可以繼續使用 Vue 2 的 Options API,但隨著程式碼邏輯的增加,看似有條理的分類,其實對於理解及維護上沒有想像中便利。Vue 3 提出的組合式 API (Composition API) 則是以邏輯功能來進行分類,你可以將所有與某個功能的 data、computed、methods 與 watch 等,寫在同一個段落行程一個區塊。
下圖中每種邏輯問題所需要得程式碼使用相同顏色表示,當使用 Composition API 重構後,同一個邏輯功能將會集中在同一個區塊,也使得複雜的元件能有更好的可讀性。
在 Options API 可以使用 mixin 來引入可以重複使用的程式碼,讓不同的元件可以共用函式方法,但隨著專案變大,同一個元件可能使用 mixin 同時來引用許多的共用函式,這將導致容易產生命名衝突、元件間的耦合與來源不夠清晰等問題。
Vue 3 為我們帶來了組合式 API,實現了更乾淨的程式碼編排與高效的邏輯重用,組合式函式 (Composables)也基於組合式 API 來進行封裝這些可複用的邏輯,更解決了使用 mixin 實現共用函式的缺點。
在 Nuxt 3 中要建立一個組合式函式 (Composables) 我們可以在 composables 目錄下編寫,這些常用的函式,將會被 Nuxt 3 自動載入做使用,實現在各個元件使用這些函式方法。
首先,我們新增 ./composables/useCounter.js,內容如下:
export default function () {
  const count = ref(0)
  const increment = () => {
    count.value += 1
  }
  return {
    count,
    increment
  }
}
Nuxt 自動導入的特性,現在我們就能在其他元件中使用 useCounter 組合式函式。
新增 ./pages/count.vue,內容如下:
<template>
  <div class="flex flex-col items-center">
    <span class="mt-8 text-4xl text-gray-700">{{ count }}</span>
    <button
      class="my-6 rounded-sm bg-sky-600 py-2 px-4 text-base font-medium text-white hover:bg-sky-700 focus:outline-none focus:ring-2 focus:ring-sky-500 focus:ring-offset-2"
      @click="increment"
    >
      增加 1
    </button>
  </div>
</template>
<script setup>
const { count, increment } = useCounter()
</script>
前面範例使用的 useCounter() 是 Nuxt 3 從 ./composables/useCounter.js 自動載入的,而且 Nuxt 3 的組合式函式的名稱,有兩種方式會影響使用時的函式名稱,不過也建議在建立組合式函式可以使用 use 作為開頭來加以識別。
如果在檔案內使用的是預設匯出,那麼這個組合式函式在使用時,即對應檔案名稱,檔案名稱可以是小寫駝峰式 (Camel case) 或烤肉串 (Kebab case),例如建立 ./composables/useCounter.js 或 ./composables/use-counter.js 檔案內容如下,使用時組合式函式為小寫駝峰式(Camel case) 名為 useCounter。
export default function () {
  const count = ref(0)
  const increment = () => {
    count.value += 1
  }
  return {
    count,
    increment
  }
}
如果建立組合式函式時,使用的是有具名的匯出,那麼組合式函式對應的名稱,就不是檔案名稱,而是檔案內 export 出來的名稱。
例如,建立 ./composables/count.js,檔案內容如下,組合式函式名稱就不會是檔案名稱 count,而是具名導出的名稱 useCounter。
export const useCounter = () => {
  const count = ref(0)
  const increment = () => {
    count.value += 1
  }
  return {
    count,
    increment
  }
}
composables 目錄下,Nuxt 3 會自動掃描 .js, .ts 與 .vue 副檔名的檔案,但只有最上層的檔案,才會自動的被載入為組合式函式,以下面這個目錄結構為例,只有 ./composables/useCounter.js 才會被正確的自動載入。
composables/
├── time/
│   └── useDateFormat.js
└── useCounter.js
下列這種形式,./composables/time/index.js 也能正確的自動載入:
composables/
├── time/
│   └── index.js
└── useCounter.js
如果你想讓巢狀的目錄結構下也能被 Nuxt 自動掃描載入,那麼你可以使用下面兩種方法:
[推薦]配置 ./composables/index.js 將目錄下的函式於這裡整理並匯出你需要的作為組合式函式。
修改 nuxt.config.ts 檔案,配置自動載入額外掃描 composables 下的巢狀目錄。
export default defineNuxtConfig({
  imports: {
    dirs: [
      // 掃描 composables 目錄頂層
      'composables',
      // 掃描深度一層的特定檔案
      'composables/*/index.{ts,js,mjs,mts}',
      // 掃描整個 composables 目錄下的檔案
      'composables/**'
    ]
  }
})
不論在 Nuxt 3 或是 Vue 3,組合式函式 (Composables) 都是能幫助你在整個網站可以共用函式的方法,目前也有專案 VueUse 提供了常用與實用的組合式函式集合,能幫我們省去不少開發時間與提升重複使用性。
感謝大家的閱讀,這是我第一次參加 iThome 鐵人賽,請鞭小力一些,也歡迎大家給予建議 :)
如果對這個 Nuxt 3 系列感興趣,可以訂閱接收通知,也歡迎分享給喜歡或正在學習 Nuxt 3 的夥伴。