vue的组件通信方式

以下这些方式都可以传递数据和方法,其中传递方法可以相当于反向传递,非常灵活。

父传子:props

1
2
3
4
<!--假定父组件给子组件传递(数据、方法)-->
<template>
<child :msg="msg" :fun="fun"></child>
</template>
1
2
3
4
5
6
7
8
<!--子组件通过defineProps接收后可以直接使用-->
<template>
<div>{{msg}}</div>
<button @click="fun">点击</button>
</template>
<script>
defineProps(['msg', 'fun'])
</script>

通过fun可以调用父组件的方法,从而进一步从子传数据到父组件中

子传父:emit和自定义事件

1
2
3
4
5
6
7
8
9
<template>
<!-- 父组件中给子组件绑定自定义事件和对应回调 -->
<child @my-event="myEvent"></child>
</template>
<script>
function myEvent(data) {
console.log(data)
}
</script>
1
2
3
4
5
6
7
8
<template>
<!-- 子组件中通过$emit触发自定义事件 -->
<button @click="emit('my-event', data)">点击</button>
</template>
<script>
const data = ref('hello')
defineEmits(['my-event'])
</script>

emitter任意组件通信

某一组件的click事件绑定如emitter('my-event', data)

在另一组件中通过emitter.on('emitter', data => {})接收,最好在unmounted中销毁emitter.off('my-event')

v-model

在父组件中绑定v-model:data=datavalue,子组件中

1
2
3
4
5
6
7
8
<template>
<input :value="data" @input="$emit('update:data', $event.target.value)">
</template>

<script>
defineProps(['data'])
defineEmits(['update:data'])
</script>

$attrs实现祖孙通信

由于子组件未通过defineProps接收的属性都存在attrs中,因此可以通过中间组件传递attrs中,因此可以通过中间组件传递attrs,最后由孙组件通过defineProps接收需要的方法和值

因此除了中间组件多了绑定$attrs外,其他和Props一样

refsrefs和parent实现父子通信

通过$refs可以获取子元素中所有通过defineExpose暴露的属性和方法

在父组件中绑定事件的回调函数,并传入$refs

1
2
3
4
5
// 子组件
let data = ref('hello')
defineExpose({
data
})
1
2
3
4
5
6
7
8
9
10
11
12
13
<template>
<child ref="child"></child>
<button @click="fun($ref)">点击</button>
</template>
<script>
const child = ref()
function fun(refs) {
console.log(refs)
// 结构是{child: {data(Proxy): 'hello'}}
console.log(refs.child.data)
// 会被深层解包,输出hello
}
</script>

$parent则适用于子组件获取父的属性和方法

provide和inject:祖先传后代

在祖先组件中通过provide提供数据,后代组件直接通过inject接收数据

1
2
3
4
5
// 祖先组件,可以同时传递方法、数据
provide('dataContent', {data,fun})

// 后代组件,可以设置默认值,并让ts隐式推断数据类型和方法参数类型
const {data,fun} = inject('dataContent', {data: 'hello', fun: () => {console.log('hello')}})