「这是我参与11月更文挑战的第1天,活动详情查看:2021最后一次更文挑战」
组件间通信方式
常用传参
props (组件间传参)
vuex (统一状态管理)
eventBus (中央事件总线)
自定义事件 ($emit,$on)
不常用传参
- 边界情况
- $parent
- $children
- $root
- $ref
- provide/inject
- 非props
- $attrs
- $listeners
实操
eventBus
class bus{
constructor(){
this.callbacks = {}
}
$on(name,fn){
this.callbacks[name] = this.callbacks[name] || []
this.callbacks[name].push(fn)
}
$emit(name,ages){
if(this.callbacks[name]) this.callbacks[name].forEach(cb => cb(ages))
}
}
vue.prototype.$bus = new bus()
$children
不能保证顺序
// 父元素
<template>
<div id="home">
<child />
<button @click="goHome">回家吃饭</button>
</div>
</template>
<script>
import child from './components/child.vue'
export default{
compoents:{child},
methods:{
goHome(){
// 调用child内的eat方法
this.$children[0].eat()
}
}
}
</script>
$attrs
<template>
// 父元素直接传入msg,不使用props接收
<div>{{$attrs.msg}}</div>
</template>
$listeners
调用父元素方法 父组件
<template>
<div class="home">
<child2 msg="这里是Home" @click="onClick"/>
</div>
</template>
<script>
import child2 from '@/components/child2.vue'
export default {
name: 'Home',
components: {
child2
},
methods:{
onClick(){
console.log('Home方法',this)
}
}
}
</script>
子组件
<template>
<!--触发父元素的方法,点击打印的this在父组件中-->
<button v-on="$listeners">click</button>
</template>
provide/inject
高阶组件库
深层次传递,只要上层级元素有,底层元素无论在哪里都能接收到,通用组件库开发时可用(element Ui,中十分常用)
上层组件
<script>
export default{
provide:{
return {
foo:'fooooo'
}
}
}
</script>
底层组件
export default {
inject:['foo']
inject:{bar:{from:'foo'}}
}
小Demo
// 父组件
<template>
<a-vue @cut="cut" :name="name"></a-vue>
</template>
<script setup>
// 在这种语法糖下,不用将做额外处理,就可以使用
import AVue from 'xxx/Avue.vue'
import {ref} from 'vue'
let name = ref('韩梅梅')
const cutName = (e) =>{
console.log(e)
switch(name.value){
case '韩梅梅':
name.value = 'rousi'
break
case 'rousi':
name.value = '韩梅梅'
break
}
}
</script>
// 子组件 AVue
<template>
<a-component :name=“name” @cut=“emits('cut')"></a-component>
</template>
<scrip setup>
import AComponent from 'xxx/AComponent.vue'
// 一般在vue3中选择用一个变量接住defineProps传来的方法
// 在版本比较新的vue3中不用引入props和emits方法就可以直接使用
let props = defineProps({
name:String
})
defineProps({
name:String
})
let emits = defineEmits([‘cut’])
</scrip>
// 孙组件 AComponent
<template>
<div>{{props.name}}</div>
<input type="submit" @click="emits" >
</template>
<script setup>
const props = defineProps({
name:String
})
const emits = defomeEmits(['cut'])
</script>
这样还只是两层的props,如果更深入呢
我们可以选择provide/inject 配合computed(计算属性使用)
// 父组件
<template>
<a-vue @cut="cut" :name="name"></a-vue>
</template>
<script setup>
// 在这种语法糖下,不用将做额外处理,就可以使用
import AVue from 'xxx/Avue.vue'
import {ref} from 'vue'
let name = ref('韩梅梅')
const cutName = (e) =>{
console.log(e)
switch(name.value){
case '韩梅梅':
name.value = 'rousi'
break
case 'rousi':
name.value = '韩梅梅'
break
}
}
</script>
// 子组件 AVue
<template>
// 不在使用 : @ 的方式引入
<a-component></a-component>
</template>
<scrip setup>
import AComponent from 'xxx/AComponent.vue'
import {computed,provide} from 'vue'
// 使用解构,给script内部使用
let {name} = defineProps({
name:String
})
let emits = defineEmits([‘cut’])
// 使用计算属性将值改变为响应式
let name = computed(()=>name)
// 将其注入
provide('name',name)
</scrip>
// 孙组件 AComponent
<template>
<div>{{name}}</div>
<input type="submit" @click="cut" >
</template>
<script setup>
// 这里需要使用inject,将其引用
import {inject} from 'vue'
// 这里注入的方法就和平时一样正常去使用
const cut = inject('cut')
const name = inject('name')
</script>