Vue3 + TS + Vite 父子組件間如何通信?
組件之間傳值,大家都很熟悉,涉及到 VUE3 +TS 好多同學就無從下手了,所以分享這篇文章,希望看完后提起 VUE3+TS 能夠不慌不忙。
平時使用的函數(shù)如:ref、reactive、watch、computed 等需要先引入才能使用,但是本篇文章介紹的 defineProps、withDefaults、defineEmits、defineExpose 都是開箱即用的函數(shù),無需引入。
父向子傳值:defineProps
在父組件內(nèi)給子組件傳值時,通過 v-bind 綁定一個數(shù)據(jù),然后子組件使用 defineProps 接收數(shù)據(jù)。
可以傳遞的數(shù)據(jù)有兩種:字符串類型 和 非字符串類型。字符串類型不需要 v-bind,非字符串需要使用 v-bind,可以簡寫成冒號(:)。
/* 父組件代碼 */<template> 父組件 <child-com title="父組件向子組件傳值" :list="list"></child-com></template><script lang="ts" setup>import ChildCom from './component/ChildCom.vue'const list: Array<number> = [1, 2, 3, 4, 5]</script>
子組件接收的時候使用 defineProps,需要注意的是我們使用 TS 需要加類型限制,如果不是 TS 的可以直接使用。
TS 語法使用:
defineProps<{title: string; data: number[]}>()
非 TS 語法使用:
defineProps({title: { default: "", type: string }, list: Array})
對應上邊父組件傳值,使用 TS 語法接收的子組件代碼為:
<template> 子組件 {{ title }} {{ list }}</template><script lang="ts" setup>interface DefineProp { title: string list: Array<number>}defineProps<DefineProp>()</script>
默認值:withDefaults
在非 TS 語法中,default 可以設置默認值,在 TS 語法中,如何設置默認值呢?
withDefaults 是一個無需引入開箱即用的函數(shù),可以接收兩個參數(shù),第一個用于defineProps 接收參數(shù),第二個參數(shù)是一個對象用于設置默認值。
使用方式1:分離模式
type Props = {title?: string; list?: number[]}withDefaults(defineProps<Props>(), {title: "默認值", list: () => [1, 2]})
使用方式2:組合模式
widthDefault(defineProps<{ title?: string, list?: number[] }>(), {title: "默認值", list: () => [1, 2]})
給上邊的子組件添加默認值代碼如下:
<template> 子組件 <br /> {{ title }} <br /> {{ list }}</template><script lang="ts" setup>interface DefineProp { title?: string list?: Array<number>}withDefaults(defineProps<DefineProp>(), { title: '設置title默認值', list: () => [1, 2],})</script>
將父組件中傳的值刪除掉之后,發(fā)現(xiàn)設置的默認值就展示出來了。
子向父傳值:defineEmits
子組件給父組件進行傳值時,都是通過派發(fā)事件,去觸發(fā)父組件中的事件并接收值。
在子組件綁定一個 @click 事件,然后通過 defineEmits 注冊自定義事件,當點擊 @click 事件時觸發(fā) emit 去調(diào)用注冊事件,然后傳遞參數(shù)。
非 TS 聲明語法
// clickname 父組件自定義事件名let emit = defineEmits([ 'clickname' ])const postV = () => {emit('clickname', '傳遞的值或變量')}
TS 聲明語法
// clickname 父組件自定義事件名let emit = defineEmits<{(e: 'clickname', str: string): void}>()const postV = (str: string): void => {emit('clickname', str)}
如果是多個自定義事件,寫法如下:
type Person = { name: string age: number}let emit = defineEmits<{ (e: 'clickname', str: string): void (e: 'getData', per: Person): void}>()const postV = (str: string): void => {emit('clickname', str)}const postVData = (per: Person): void => {emit('getData', per)}
我們在子組件內(nèi),使用 defineEmits 添加派發(fā)事件:
<template> 子組件 <button ="postV">子向父傳值</button> <button ="postVal('傳遞字符串')">子向父傳data</button></template><script lang="ts" setup>import { reactive } from 'vue'// 子向父傳值type Person = { name: string age: number}const per = reactive<Person>({ name: 'qq', age: 18,})const emit = defineEmits<{ (e: 'clickname', per: Person): void (e: 'getData', data: string): void}>()const postV = (per: Person): void => { emit('clickname', per)}const postVal = (data: string): void => { emit('getData', data)}</script>
父組件內(nèi)使用自定義事件,接收子組件傳遞來的數(shù)據(jù):
<template> 父組件 <child-com ="getChildVal" ="getChildData" ></child-com></template><script lang="ts" setup>iimport ChildCom from './component/ChildCom.vue'const getChildVal = (per: { name: string; age: number }): void => { console.log('per:', per)}const getChildData = (data: string): void => { console.log('data', data)}</script>
defineExpose
子組件向父組件傳值時,除了使用 defineEmits 之后,也可以使用 defineExpose ,它是通過把組件自己的屬性暴露出去,父組件先獲取到子組件,再獲取屬性值。
defineExpose 接收一個對象參數(shù),包含需要傳遞的屬性。
defineExpose({name, count, ....})
在子組件內(nèi),定義和暴露需要傳遞的屬性:
<template> 子組件</template><script lang="ts" setup>const count: number = 1defineExpose({ count,})</script>
在父組件內(nèi)使用 ref 獲取到子組件,然后打印屬性:
<template> 父組件 <child-com ref="child"></child-com> <button ="getProp">獲取子組件屬性</button></template><script lang="ts" setup>import ChildCom from './component/ChildCom.vue'import { ref } from 'vue'const child: HTMLElement = ref()const getProp = (): void => { console.log(child.value.count)}</script>