本文 AI 產出,尚未審核
Vue3 元件基礎:建立與匯入元件(import / export)
簡介
在 Vue3 中,元件是構建任何 UI 的基本單位。無論是簡單的按鈕、複雜的表單,或是整頁的佈局,都會被拆解成可重用的元件。學會 建立、匯出(export)以及 匯入(import)元件,是使用 Vue3 開發的第一步,也是未來維護、擴充與團隊協作的基礎。
本篇文章將從最基本的單檔元件(Single File Component, SFC)說起,說明如何在 *.vue 檔案中 export 元件,並在其他檔案中 import 使用。透過實作範例,我們會看到在真實專案中如何組織檔案、避免命名衝突,以及提升開發效率的最佳實踐。
核心概念
1. 單檔元件(SFC)的基本結構
Vue3 推薦使用 單檔元件(.vue),其內部由三個主要區塊組成:
| 區塊 | 目的 | 常見屬性 |
|---|---|---|
<template> |
定義 HTML 標記 | v-if、v-for 等指令 |
<script> |
撰寫 JavaScript/TypeScript 邏輯 | setup、export 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 default 與 export const,但匯入時只寫預設 |
確認匯入語法:import MyComp, { helper } |
| 樣式污染 | 未使用 scoped,導致全局 CSS 被覆寫 |
在 <style scoped> 中撰寫元件樣式,或使用 CSS Modules |
最佳實踐
- 每個檔案只保留一個預設匯出,讓匯入時的名稱直觀且易於維護。
- 具名匯出 用於共用工具函式或多個小型子元件,減少檔案數量。
- 使用 TypeScript(
<script lang="ts">)時,defineComponent能提供更好的型別推斷。 - 自動化檢查:加入 ESLint +
eslint-plugin-vue,可捕捉未註冊的元件或錯誤的匯入路徑。 - 懶載入(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 元件!