本文 AI 產出,尚未審核

Vue3 元件基礎:建立與匯入元件(import / export)

簡介

在 Vue3 中,元件是構建任何 UI 的基本單位。無論是簡單的按鈕、複雜的表單,或是整頁的佈局,都會被拆解成可重用的元件。學會 建立匯出(export)以及 匯入(import)元件,是使用 Vue3 開發的第一步,也是未來維護、擴充與團隊協作的基礎。

本篇文章將從最基本的單檔元件(Single File Component, SFC)說起,說明如何在 *.vue 檔案中 export 元件,並在其他檔案中 import 使用。透過實作範例,我們會看到在真實專案中如何組織檔案、避免命名衝突,以及提升開發效率的最佳實踐。


核心概念

1. 單檔元件(SFC)的基本結構

Vue3 推薦使用 單檔元件(.vue),其內部由三個主要區塊組成:

區塊 目的 常見屬性
<template> 定義 HTML 標記 v-ifv-for 等指令
<script> 撰寫 JavaScript/TypeScript 邏輯 setupexport default
<style> 撰寫 CSS(可加 scoped lang="scss"scoped
<!-- MyButton.vue -->
<template>
  <button @click="handleClick">{{ label }}</button>
</template>

<script>
export default {
  name: 'MyButton',
  props: {
    label: { type: String, default: 'Click Me' }
  },
  methods: {
    handleClick() {
      this.$emit('click')
    }
  }
}
</script>

<style scoped>
button {
  padding: 0.5rem 1rem;
  background: #42b983;
  color: #fff;
  border: none;
  border-radius: 4px;
}
</style>

重點export default 會把整個物件 匯出 為此檔案的預設元件,之後才能在其他檔案 import


2. 匯出(export)方式

匯出方式 語法 何時使用
預設匯出 (export default) export default { … } 每個檔案只會有 一個 主要元件時最常用
具名匯出 (export const …) export const MyComponent = { … } 同檔案需要匯出多個元件或輔助函式時

2-1. 預設匯出範例

// Counter.vue
export default {
  name: 'Counter',
  data() {
    return { count: 0 }
  },
  template: `<button @click="count++">Count: {{ count }}</button>`
}

2-2. 具名匯出範例

// utilities.js
export const formatDate = (date) => {
  return new Intl.DateTimeFormat('zh-TW').format(date)
}
export const debounce = (fn, delay) => {
  let timer
  return (...args) => {
    clearTimeout(timer)
    timer = setTimeout(() => fn(...args), delay)
  }
}

在 Vue 元件中仍可使用具名匯出,例如:

<script>
export const Header = {
  name: 'Header',
  template: `<header>My Site</header>`
}
export const Footer = {
  name: 'Footer',
  template: `<footer>©2025</footer>`
}
</script>

3. 匯入(import)方式

3-1. 匯入預設匯出

import MyButton from '@/components/MyButton.vue'
// MyButton 現在是一個 Vue 元件,可直接在 template 中使用

3-2. 匯入具名匯出

import { formatDate, debounce } from '@/utils/utilities.js'

3-3. 同時匯入預設與具名

import MyComponent, { helper } from '@/components/MyComponent.vue'

小技巧:使用 別名(as)可以避免命名衝突

import { formatDate as fmtDate } from '@/utils/utilities.js'

4. 實作範例:從零建立一個「Todo List」元件套件

4-1. TodoItem.vue – 單一待辦項目

<template>
  <li :class="{ done: completed }">
    <input type="checkbox" v-model="completed" @change="emitChange" />
    <span>{{ text }}</span>
    <button @click="$emit('remove')">✕</button>
  </li>
</template>

<script>
export default {
  name: 'TodoItem',
  props: {
    text: { type: String, required: true },
    completed: { type: Boolean, default: false }
  },
  methods: {
    emitChange() {
      this.$emit('update:completed', this.completed)
    }
  }
}
</script>

<style scoped>
.done span { text-decoration: line-through; color: #777; }
li { display: flex; align-items: center; margin: 0.5rem 0; }
button { margin-left: auto; background: transparent; border: none; cursor: pointer; }
</style>

4-2. TodoList.vue – 列表容器,匯入 TodoItem

<template>
  <section>
    <h2>Todo List</h2>
    <input v-model="newTodo" @keyup.enter="addTodo" placeholder="新增待辦事項" />
    <ul>
      <TodoItem
        v-for="(item, idx) in todos"
        :key="idx"
        :text="item.text"
        :completed.sync="item.completed"
        @remove="removeTodo(idx)"
      />
    </ul>
  </section>
</template>

<script>
import TodoItem from './TodoItem.vue'   // ← 匯入預設匯出

export default {
  name: 'TodoList',
  components: { TodoItem },             // 在此註冊
  data() {
    return {
      newTodo: '',
      todos: []                         // [{ text: '', completed: false }]
    }
  },
  methods: {
    addTodo() {
      if (this.newTodo.trim()) {
        this.todos.push({ text: this.newTodo, completed: false })
        this.newTodo = ''
      }
    },
    removeTodo(index) {
      this.todos.splice(index, 1)
    }
  }
}
</script>

<style scoped>
section { max-width: 400px; margin: auto; }
input { width: 100%; padding: 0.5rem; margin-bottom: 1rem; }
ul { list-style: none; padding: 0; }
</style>

4-3. 在根元件 App.vue 中匯入 TodoList

<template>
  <div id="app">
    <TodoList />
  </div>
</template>

<script>
import TodoList from '@/components/TodoList.vue'

export default {
  name: 'App',
  components: { TodoList }
}
</script>

<style>
#app { font-family: Avenir, Helvetica, Arial, sans-serif; padding: 2rem; }
</style>

5. 組織檔案的建議

src/
 ├─ components/
 │   ├─ TodoItem.vue
 │   └─ TodoList.vue
 ├─ utils/
 │   └─ date.js
 ├─ App.vue
 └─ main.js
  • 元件檔案放在 components/,每個元件自行管理樣式與邏輯。
  • 工具函式放在 utils/,使用具名匯出,方便在多個元件中共用。

常見陷阱與最佳實踐

陷阱 可能原因 解決方案
匯入路徑錯誤(找不到檔案) 相對路徑 (../) 計算錯誤 使用 別名(如 @/components)或 Vite/webpack 的 resolve.alias
命名衝突(兩個元件同名) 匯入時未使用別名 import Header as SiteHeader
忘記在 components 中註冊 匯入後直接在 template 使用 必須在 export default { components: { … } } 中註冊
預設匯出與具名匯出混用不當 同時 export defaultexport const,但匯入時只寫預設 確認匯入語法:import MyComp, { helper }
樣式污染 未使用 scoped,導致全局 CSS 被覆寫 <style scoped> 中撰寫元件樣式,或使用 CSS Modules

最佳實踐

  1. 每個檔案只保留一個預設匯出,讓匯入時的名稱直觀且易於維護。
  2. 具名匯出 用於共用工具函式或多個小型子元件,減少檔案數量。
  3. 使用 TypeScript<script lang="ts">)時,defineComponent 能提供更好的型別推斷。
  4. 自動化檢查:加入 ESLint + eslint-plugin-vue,可捕捉未註冊的元件或錯誤的匯入路徑。
  5. 懶載入(Lazy Loading):對於大型元件,使用 defineAsyncComponent 或路由層級的 import() 以提升首屏載入速度。
// 範例:懶載入 Footer 元件
import { defineAsyncComponent } from 'vue'
export default {
  components: {
    Footer: defineAsyncComponent(() => import('@/components/Footer.vue'))
  }
}

實際應用場景

場景 需求 透過 import/export 解決方式
多頁面大型後台系統 共用表格、搜尋列、分頁元件 把這些共用元件放在 components/common/,以預設匯出提供給各頁面 import 使用。
第三方 UI 套件(如 Element Plus) 只需要部分元件以減少 bundle 大小 具名匯入import { ElButton, ElDialog } from 'element-plus',配合 tree‑shaking。
團隊協作 多人同時開發同一元件庫 使用 具名匯出index.js 重新導出:
export { default as MyButton } from './MyButton.vue',讓使用者只需 import { MyButton } from '@/components'
SSR 或 Nuxt3 需要在服務端預先載入元件 仍使用標準 import,但需注意 動態匯入import())會在伺服器端同步執行。
測試 (unit test) 測試單一元件的邏輯 直接 import MyComponent from '@/components/MyComponent.vue',搭配 Vue Test Utils 測試其 props、events。

總結

  • 建立元件:在 .vue 檔案內使用 <template><script><style>,並以 export default 匯出。
  • 匯入元件:在需要的檔案中使用 import ComponentName from '@/path/Component.vue',或具名匯入工具函式。
  • 註冊與使用:匯入後必須在 components 中註冊,才能在模板內直接使用。
  • 避免常見錯誤:確認路徑、命名、註冊,並善用 scoped、別名與 lint。
  • 最佳實踐:保持每檔案單一預設匯出、適度使用具名匯出、結合懶載入與 TypeScript,提高可維護性與效能。

掌握了 import / export 的正確使用方式,你就能在 Vue3 專案中快速組合、重用與擴充元件,從小型原型到大型企業級應用皆能游刃有餘。祝你開發順利,寫出乾淨、可維護的 Vue3 元件!