组件间通信有哪些方式?
1. 组件间通信的分类
组件间通信可以按以下维度分类:
- 父子通信:props / $emit / ref / $parent / $children
- 隔代通信:provide / inject / $attrs / $listeners
- 兄弟通信:EventBus / Vuex
- 全局通信:Vuex / EventBus
2. 整理 Vue 中 8 种常规的通信方案
(1) props 传递数据
props: {
// 字符串形式
name: String, // 接收的类型参数
// 对象形式
age: {
type: Number, // 接收的类型为数值
default: 18, // 默认值为 18
required: true // age 属性必须传递
}
}
<Children name="jack" :age="18" />
(2) $emit 触发自定义事件
this.$emit('add', good)
<Children @add="cartAdd($event)" />
(3) ref
<Children ref="foo" />
this.$refs.foo // 获取子组件实例,通过子组件实例我们就能拿到对应的数据
(4) EventBus
// 创建一个中央事件总线类
class Bus {
constructor() {
this.callbacks = {} // 存放事件的名字
}
$on(name, fn) {
this.callbacks[name] = this.callbacks[name] || []
this.callbacks[name].push(fn)
}
$emit(name, args) {
if (this.callbacks[name]) {
this.callbacks[name].forEach(cb => cb(args))
}
}
}
// main.js
Vue.prototype.$bus = new Bus() // 将 $bus 挂载到 vue 实例的原型上
// 另一种方式:Vue 已经实现了 Bus 的功能
Vue.prototype.$bus = new Vue()
// Children1.vue
this.$bus.$emit('foo')
// Children2.vue
this.$bus.$on('foo', this.handle)
vm.$on(event, callback) 触发当前实例上的事件。附加参数都会传给监听器回调。多次给同一个事件绑定 callback 不会覆盖,而是会依次执行。
(5) $parent / $root(兄弟 / 根)
// 兄弟组件
this.$parent.on('add', this.add)
// 另一个兄弟组件
this.$parent.emit('add')
(6) $attrs 与 $listeners
<!-- 给 Grandson 隔代传值,communication/index.vue -->
<Child2 msg="lalala" @some-event="onSomeEvent" />
<!-- Child2 做展开 -->
<Grandson v-bind="$attrs" v-on="$listeners" />
<!-- Grandson 使用 -->
<div @click="$emit('some-event', 'msg from grandson')">
{{ msg }}
</div>
注:Vue 3 中 $listeners 已被移除,事件监听器会作为 attrs 的一部分传给子组件。
(7) provide 与 inject
祖先组件通过 provide 提供数据,后代组件通过 inject 注入数据。
// 祖先
export default {
provide() {
return { foo: 'bar' }
}
}
// 后代
export default {
inject: ['foo'],
mounted() {
console.log(this.foo) // 'bar'
}
}
(8) Vuex
actions: {
actionA(context) {
context.commit('mutationMethod')
},
actionB({ commit, state }) {
commit('mutationMethod2')
}
}
来源整理自:vue3js.cn 面试官系列



