在 Vue.js 的開發世界里,單文件組件(Single File Components,簡稱 SFC)是構建復雜應用的基石。它將 HTML、CSS 和 JavaScript 代碼封裝在一個.vue
文件中,極大地提高了代碼的可維護性和復用性。
本文將深入探討單文件組件中幾個重要特性:VCA 語法糖、computed、watch、props 與 emit,以及 provide 和 inject 的使用。
一、VCA 語法糖:讓代碼更簡潔優雅
VCA 是 Vue Composition API 的縮寫,它是 Vue 3 推出的新特性,允許開發者以函數式的方式組織組件邏輯。在單文件組件中使用 VCA 語法糖,能讓代碼更加簡潔直觀。
在 Vue 3 的單文件組件中,我們可以直接在<script>
標簽內使用 VCA 語法糖,無需額外引入defineComponent
。例如:
<template><div><p>{{ message }}</p></div>
</template><script setup>
import { ref } from 'vue';
const message = ref('Hello, Vue 3!');
</script>
在上述代碼中,<script setup>
就是 VCA 語法糖的體現。它自動進行了組件的定義,并且在該標簽內聲明的變量和函數可以直接在<template>
中使用,無需額外返回。這種寫法減少了樣板代碼,使代碼更加簡潔,邏輯更加清晰。
二、computed:高效的數據處理
computed 屬性用于基于其他響應式數據計算派生數據。它具有緩存機制,只有當依賴的響應式數據發生變化時,才會重新計算。
<template><div><p>原始數字: {{ num }}</p><p>計算后的雙倍數字: {{ doubleNum }}</p></div>
</template><script setup>
import { ref, computed } from 'vue';
const num = ref(5);
const doubleNum = computed(() => num.value * 2);
</script>
在這個例子中,doubleNum
是一個 computed 屬性,它依賴于num
。當num
的值發生變化時,doubleNum
會自動重新計算;如果num
的值不變,再次訪問doubleNum
時會直接返回緩存的結果,從而提高性能。
三、watch:監聽數據變化
watch 用于監聽響應式數據的變化,并在數據變化時執行相應的回調函數。它可以監聽單個數據,也可以監聽多個數據的變化。
<template><div><input v-model="message" /><p>{{ logMessage }}</p></div>
</template><script setup>
import { ref, watch } from 'vue';
const message = ref('');
const logMessage = ref('');
watch(message, (newValue, oldValue) => {logMessage.value = `值從 ${oldValue} 變為 ${newValue}`;
});
</script>
在上述代碼中,watch
函數監聽message
的變化。當message
的值改變時,回調函數會被觸發,更新logMessage
的值,從而在頁面上顯示數據變化的信息。
四、props 和 emit:父子組件通信的橋梁
1. props:父組件向子組件傳遞數據
props 用于父組件向子組件傳遞數據。子組件通過定義 props 來接收父組件傳遞的值。
父組件 Parent.vue:
<template><div><Child :message="parentMessage" /></div>
</template><script setup>
import Child from './Child.vue';
const parentMessage = '來自父組件的數據';
</script>
子組件 Child.vue:
<template><div><p>{{ message }}</p></div>
</template><script setup>
defineProps({message: String
});
</script>
在這個例子中,父組件Parent.vue
通過props
將parentMessage
傳遞給子組件Child.vue
,子組件通過定義message
屬性接收并使用該數據。
2. emit:子組件向父組件傳遞事件
emit 用于子組件向父組件傳遞事件和數據。子組件通過調用emit
方法觸發自定義事件,父組件通過監聽該事件來接收數據。
子組件 Child.vue:
<template><div><button @click="sendDataToParent">發送數據</button></div>
</template><script setup>
import { defineEmits } from 'vue';
const emits = defineEmits(['dataSent']);
const sendDataToParent = () => {emits('dataSent', '子組件發送的數據');
};
</script>
父組件 Parent.vue:
<template><div><Child @dataSent="handleData" /><p>{{ receivedData }}</p></div>
</template><script setup>
import Child from './Child.vue';
const receivedData = ref('');
const handleData = (data) => {receivedData.value = data;
};
</script>
在這個例子中,子組件Child.vue
通過emit
觸發dataSent
事件,并傳遞數據;父組件Parent.vue
通過監聽dataSent
事件,在handleData
函數中接收并處理子組件傳遞的數據。
五、provide 和 inject:跨層級組件通信的利器
在大型應用中,經常會遇到跨層級組件通信的需求。如果使用 props 和 emit 進行多層級傳遞,會使代碼變得繁瑣。這時,provide
和inject
就派上用場了。
provide
用于在祖先組件中提供數據,inject
用于在后代組件中注入并使用這些數據。
祖先組件 Grandparent.vue:
<template><div><Child /></div>
</template><script setup>
import Child from './Child.vue';
import { provide } from 'vue';
const sharedData = '這是共享數據';
provide('sharedData', sharedData);
</script>
后代組件 Child.vue:
<template><div><p>{{ injectedData }}</p></div>
</template><script setup>
import { inject } from 'vue';
const injectedData = inject('sharedData');
console.log(injectedData);
</script>
在這個例子中,祖先組件Grandparent.vue
通過provide
提供sharedData
,后代組件Child.vue
通過inject
注入并使用該數據,實現了跨層級的組件通信。