Vue3 組件通信和 Vue2 的區(qū)別:
- 移出事件總線盔沫,使用
mitt
代替。 -
vuex
換成了pinia
构舟。 - 把
.sync
優(yōu)化到了v-model
里面了 - 把
$listeners
所有的東西灰追,合并到$attrs
中了。 -
$children
被砍掉了狗超。
常見搭配形式
1. props
props
是使用頻率最高的一種通信方式弹澎,常用與 :父 ? 子。
父傳子:屬性值是非函數(shù)
子傳父:屬性值是函數(shù)努咐。
- 父傳子(屬性值是非函數(shù))
<child :name="name"/>
let name = ref('zs')
// 子組件接收
defineProps(['name'])
- 子傳父(屬性值是函數(shù))
// 父組件
<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','參數(shù)1','參數(shù)2')
}
3. mitt
與消息訂閱與發(fā)布(
pubsub
)功能類似,可以實(shí)現(xiàn)任意組件間通信
安裝:npm i mitt
//utils/emitter.js
// 引入 mitt
import mitt from "mitt";
// 創(chuàng)建 mitt
const emitter = mitt()
// 暴露 mitt
export default emitter
- 發(fā)送事件
import emitter from "@/utils/emitter";
const handleSend = () => {
emitter.emit('send-name', { name: '參數(shù)1' })
}
- 監(jiān)聽事件
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事件被觸發(fā)',value)
})
emitter.on('xyz',(value)=>{
console.log('xyz事件被觸發(fā)',value)
})
setInterval(() => {
// 觸發(fā)事件
emitter.emit('abc',666)
emitter.emit('xyz',777)
}, 1000);
setTimeout(() => {
// 清理事件
emitter.all.clear()
}, 3000);
4. v-model
實(shí)現(xiàn) 父?子 之間相互通信渗稍。
// 父組件
<child v-model="name" />
// v-modle 本質(zhì) 上面的是下面的簡寫
<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'])
- 綁定多個(gè)值
// 父組件
<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
用于實(shí)現(xiàn)當(dāng)前組件的父組件佩迟,向當(dāng)前組件的子組件通信(祖→孫)团滥。
$attrs
是一個(gè)對(duì)象,包含所有父組件傳入的標(biāo)簽屬性报强。
$attrs
會(huì)自動(dòng)排除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
用于 :父→子。 值為對(duì)象躺涝,包含所有被ref
屬性標(biāo)識(shí)的DOM
元素或組件實(shí)例厨钻。
$parent
用于:子→父。 值為對(duì)象坚嗜,當(dāng)前組件的父組件實(shí)例對(duì)象夯膀。
- ref 獲取子組件數(shù)據(jù)
// 父組件
<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
實(shí)現(xiàn)祖孫組件直接通信
在祖先組件中通過provide
配置向后代組件提供數(shù)據(jù)
在后代組件中通過inject
配置來聲明接收數(shù)據(jù)
// 祖組件
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
- 默認(rèn)插槽
// 父組件
<child title="默認(rèn)插槽">
<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="默認(rèn)插槽">
<template #c1>
我是c1內(nèi)容
</template>
<template v-slot:c2>
我是c2內(nèi)容
</template>
</child>
// 子組件
<div class="child">
<h3>{{title}}</h3>
<slot name='c1'></slot>
<slot name='c2'></slot>
</div>
defineProps(['title'])
- 作用域插槽
數(shù)據(jù)在組件的自身苍蔬,但根據(jù)數(shù)據(jù)生成的結(jié)構(gòu)需要組件的使用者來決定诱建。
// 父組件
<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>
總結(jié)
-
props
父傳子,子傳父 -
自定義事件
子傳父 -
mitt
任意組件通信 -
v-model
父傳子碟绑,子傳父 -
$attrs
父傳子俺猿,父傳孫,祖孫通信 -
$refs
父傳子 -
$pare
子傳父 -
provide格仲、inject
祖?zhèn)魍ㄐ?/li> -
pinia
任意組件通信 -
slot
父傳子押袍,子傳父