Vue3 组件通信和 Vue2 的区别:
- 移出事件总线,使用
mitt
代替。 -
vuex
换成了pinia
。 - 把
.sync
优化到了v-model
里面了 - 把
$listeners
所有的东西,合并到$attrs
中了。 -
$children
被砍掉了。
常见搭配形式
![](https://img.haomeiwen.com/i27099288/6849f7303faa51ae.png)
1. props
props
是使用频率最高的一种通信方式,常用与 :父 ↔ 子。
父传子:属性值是非函数
子传父:属性值是函数。
- 父传子(属性值是非函数)
<child :name="name"/>
let name = ref('zs')
// 子组件接收
defineProps(['name'])
- 子传父(属性值是函数)
// 父组件
<child :getName="getName" />
const getName= (value) => {
console.log(value);
}
// 子组件
defineProps(['getName'])
<el-button @click="getName('我是子组件的值')">传值给父组件</el-button>
2. 自定义事件
概述:自定义事件常用于:子 => 父。
// 父组件
<child @send-name="getName" />
const getName = (v1, v2) => {
console.log(v1, v2);
}
//子组件
<el-button @click="handleSend">传值给父组件</el-button>
const $emits = defineEmits(['send-name'])
const handleSend = ()=>{
$emits('send-name','参数1','参数2')
}
3. mitt
与消息订阅与发布(
pubsub
)功能类似,可以实现任意组件间通信
安装:npm i mitt
//utils/emitter.js
// 引入 mitt
import mitt from "mitt";
// 创建 mitt
const emitter = mitt()
// 暴露 mitt
export default emitter
- 发送事件
import emitter from "@/utils/emitter";
const handleSend = () => {
emitter.emit('send-name', { name: '参数1' })
}
- 监听事件
import emitter from "@/utils/emitter";
// 绑定事件
emitter.on('send-name', (obj) => {
console.log(obj)
})
// 卸载
onUnmounted(()=>{
emitter.off('send-name')
})
- 示例
// 绑定事件
emitter.on('abc',(value)=>{
console.log('abc事件被触发',value)
})
emitter.on('xyz',(value)=>{
console.log('xyz事件被触发',value)
})
setInterval(() => {
// 触发事件
emitter.emit('abc',666)
emitter.emit('xyz',777)
}, 1000);
setTimeout(() => {
// 清理事件
emitter.all.clear()
}, 3000);
4. v-model
实现 父↔子 之间相互通信。
// 父组件
<child v-model="name" />
// v-modle 本质 上面的是下面的简写
<child :modelValue="name" @update:model-value="name = $event" />
let name = ref('my name is zs')
// 子组件 child
<input type="text" :value="modelValue" @input="emit('update:model-value',$event.target.value)">
defineProps(['modelValue'])
const emit = defineEmits(['update:model-value'])
- 绑定多个值
// 父组件
<child v-model:name1="name1" v-model:name2="name2" />
let name1 = ref('zs')
let name2 = ref('ls')
// 子组件
<el-button @click="handleChange">开始传值</el-button>
defineProps(['name1', 'name2'])
const emit = defineEmits(['update:name1', 'update:name2'])
const handleChange = () => {
emit('update:name1','zs1')
emit('update:name2','ls1')
}
5. $attrs
$attrs
用于实现当前组件的父组件,向当前组件的子组件通信(祖→孙)。
$attrs
是一个对象,包含所有父组件传入的标签属性。
$attrs
会自动排除props
中声明的属性
// 父
<child :name1="name1" :name2="name2" :name3="name3" />
let name1 = ref('name1')
let name2 = ref('name2')
let name3 = ref('name3')
// 子
<son v-bind="$attrs" />
defineProps(['name1'])
// 孙
defineProps(['name2', 'name3'])
6. refs、parent
$refs
用于 :父→子。 值为对象,包含所有被ref
属性标识的DOM
元素或组件实例。
$parent
用于:子→父。 值为对象,当前组件的父组件实例对象。
- ref 获取子组件数据
// 父组件
<child ref="childRef" />
let childRef = ref()
const getChild = () => {
console.log(childRef.value.age);
console.log(childRef.value.name);
}
// 子组件
let name = ref('zs')
let age = ref(16)
defineExpose({ name, age })
- parent 子传父
// 父组件
let parentAge = ref(12)
const printName = () => {
console.log('我是名称');
}
defineExpose({ parentAge,hanshu: printName })
// 子组件
<button @click="getParent($parent)">年龄-1</button>
const getParent = (parent) => {
parent.hanshu()
parent.parentAge-=1
}
7. provide、inject
实现祖孙组件直接通信
在祖先组件中通过provide
配置向后代组件提供数据
在后代组件中通过inject
配置来声明接收数据
// 祖组件
let name = ref('zs')
let age = ref(18)
const updateAge = () => {
age.value += 1
}
provide('name', name)
provide('ageContent', { age, updateAge })
// 孙组件
let name = inject('name')
let { age, updateAge } = inject('ageContent')
setInterval(() => {
updateAge()
}, 1000);
8. pinia
9. slot
- 默认插槽
// 父组件
<child title="默认插槽">
<ul>
<li v-for="i in 10" :key="i">{{i}}</li>
</ul>
</child>
// 子组件
<div class="child">
<h3>{{title}}</h3>
<slot></slot>
</div>
defineProps(['title'])
- 具名插槽
// 父组件 v-slot: 可以简写成#
<child title="默认插槽">
<template #c1>
我是c1内容
</template>
<template v-slot:c2>
我是c2内容
</template>
</child>
// 子组件
<div class="child">
<h3>{{title}}</h3>
<slot name='c1'></slot>
<slot name='c2'></slot>
</div>
defineProps(['title'])
- 作用域插槽
数据在组件的自身,但根据数据生成的结构需要组件的使用者来决定。
// 父组件
<div class="parent">
<child v-slot="params">
<ul>
<li v-for="item in params.dataList" :key="item.age">{{item.name}}</li>
</ul>
</child>
<child v-slot:default="params">
<ol>
<li v-for="item in params.dataList" :key="item.age">{{item.name}}</li>
</ol>
</child>
<child #default="params">
<dl>
<dt>{{ params.title }}</dt>
<dd v-for="item in params.dataList" :key="item.age">{{item.name}}</dd>
</dl>
</child>
</div>
// 子组件
<div class="child">
<slot :dataList="dataList" title="作用域插槽"></slot>
</div>
<script setup>
let dataList = reactive([
{ name: 'zs', age: 11 },
{ name: 'ls', age: 22 },
{ name: 'wu', age: 33 },
])
</script>
总结
-
props
父传子,子传父 -
自定义事件
子传父 -
mitt
任意组件通信 -
v-model
父传子,子传父 -
$attrs
父传子,父传孙,祖孙通信 -
$refs
父传子 -
$pare
子传父 -
provide、inject
祖传通信 -
pinia
任意组件通信 -
slot
父传子,子传父
网友评论