在 Vue 中創建子組件需要遵循組件化開發的核心原則,并注意數據流、通信機制、復用性等關鍵點。以下是詳細步驟和注意事項,結合代碼示例說明:
一、創建子組件的步驟
1. 定義子組件
創建一個 .vue
文件(單文件組件),包含模板、邏輯和樣式:
<!-- ChildComponent.vue -->
<template><div class="child"><h3>{{ title }}</h3><button @click="handleClick">點擊我</button></div>
</template><script>
export default {props: {title: {type: String,required: true}},emits: ['button-clicked'], // 聲明觸發的事件methods: {handleClick() {this.$emit('button-clicked', '來自子組件的消息');}}
};
</script><style scoped>
.child {border: 1px solid #ccc;padding: 20px;
}
</style>
2. 在父組件中引入并使用子組件
<!-- ParentComponent.vue -->
<template><div class="parent"><ChildComponent title="子組件標題"@button-clicked="handleChildEvent"/></div>
</template><script>
import ChildComponent from './ChildComponent.vue';export default {components: {ChildComponent},methods: {handleChildEvent(message) {console.log(message); // 輸出:"來自子組件的消息"}}
};
</script>
二、關鍵注意事項
1. 組件通信
-
父 → 子:通過
props
傳遞數據。- 單向數據流:子組件不能直接修改
props
,需通過事件通知父組件修改。
<!-- 父組件傳遞數據 --> <ChildComponent :title="parentTitle" /><!-- 子組件接收 --> <script> export default {props: ['title'] }; </script>
- 單向數據流:子組件不能直接修改
-
子 → 父:通過
$emit
觸發事件。<!-- 子組件觸發事件 --> <button @click="$emit('update', newValue)">提交</button><!-- 父組件監聽 --> <ChildComponent @update="handleUpdate" />
2. 插槽(Slots)
用于在子組件中插入動態內容,增強復用性:
<!-- 子組件 ChildComponent.vue -->
<template><div class="card"><slot name="header"></slot><slot>默認內容(當父組件不傳遞內容時顯示)</slot></div>
</template><!-- 父組件使用 -->
<ChildComponent><template #header><h2>自定義標題</h2></template><p>這是父組件插入的內容</p>
</ChildComponent>
3. 作用域樣式
使用 <style scoped>
隔離子組件樣式,避免全局污染:
<style scoped>
/* 僅對當前組件生效 */
.child {background: #f0f0f0;
}
</style>
4. 性能優化
-
避免不必要的渲染:
- 使用
v-once
靜態緩存:<div v-once>{{ staticContent }}</div>
- 復雜數據使用
computed
屬性緩存:computed: {filteredList() {return this.list.filter(item => item.active);} }
- 使用
-
異步組件:按需加載子組件(Vue 3):
const ChildComponent = defineAsyncComponent(() => import('./ChildComponent.vue'));
5. Props 設計規范
-
類型檢查:明確數據類型和默認值。
props: {count: {type: Number,default: 0,validator: (value) => value >= 0} }
-
復雜對象傳遞:使用
v-bind
綁定對象:<!-- 父組件 --> <ChildComponent v-bind="userData" /><!-- 等價于 --> <ChildComponent :name="userData.name" :age="userData.age" />
6. 事件命名規范
- 自定義事件名:建議使用 kebab-case(短橫線命名),避免與原生事件沖突。
<!-- 子組件觸發 --> this.$emit('custom-event', data);<!-- 父組件監聽 --> <ChildComponent @custom-event="handler" />
三、Vue 3 的新特性
1. 組合式 API(Composition API)
更靈活的邏輯復用方式(推薦在復雜組件中使用):
<script setup>
import { ref, defineProps, defineEmits } from 'vue';const props = defineProps({title: String
});
const emit = defineEmits(['button-clicked']);const handleClick = () => {emit('button-clicked', '來自子組件的消息');
};
</script>
2. 多個 v-model
綁定
支持在單個組件上綁定多個 v-model
:
<!-- 父組件 -->
<ChildComponent v-model:name="userName" v-model:age="userAge" /><!-- 子組件 -->
<script setup>
defineProps(['name', 'age']);
defineEmits(['update:name', 'update:age']);
</script>
四、常見問題與解決方案
1. Props 未觸發更新
- 問題:直接修改對象/數組類型的
props
(如props.list.push(newItem)
)。 - 解決:深拷貝數據或通過事件通知父組件修改。
2. 樣式污染
- 問題:未使用
scoped
導致樣式影響全局。 - 解決:始終添加
<style scoped>
或使用 CSS Modules。
3. 事件未觸發
- 問題:未在子組件中聲明
emits
(Vue 3 中會警告)。 - 解決:顯式聲明
emits
選項。
五、總結
核心要點 | 實現方式 |
---|---|
創建子組件 | 單文件組件(.vue ),包含 <template> , <script> , <style> |
父子通信 | props (父 → 子),$emit (子 → 父) |
插槽 | <slot> 插入動態內容,<slot name="header"> 具名插槽 |
樣式隔離 | <style scoped> 或 CSS Modules |
性能優化 | v-once 、computed 、異步組件 |
Vue 3 特性 | 組合式 API、<script setup> 、多個 v-model |
通過合理設計組件職責、規范通信機制、優化渲染性能,可以構建 高復用、易維護 的 Vue 子組件。