通讯的目的
通信[2]是发送者通过某种媒体以某种格式来传递信息到接收者,信息以某种形式(如语音、文字)传递。
组件通讯的目的是传递信息,数据是信息的载体,状态是变化的数据[3]。
组件通讯分类
- 父子
- 兄弟
- 祖孙
组件通讯方式
- props/$emit
- $children/$parent($root)
- provide/inject
- refs/ref
- eventBus
- vuex等状态管理库
- localStorage、sessionStorage、indexDB、$route.query||params
- $attrs/$listeners
props/$emit
直接进行父子组件通讯,祖孙使用props会存在逐级透传问题。
注意:props不可改值
$children/$parent($root)
$parent可以拿到父组件实例(父组件唯一),可以使用:this.$parent.emit(), this.$parent.on(), this.$parent.属性;
$children在vue3中移除了,在vue2中可使用:官网建议应急使用,且$children数组无法保证顺序。
provide/inject
适合祖孙组件间通讯,用以解决props逐级透传问题[1]。
注意:
- inject数据非响应式,可以与computed配合使用
- inject注入在data(){}之前
- 可以使用Symbol()保证key唯一
refs/ref
this.$refs.childern_ref可以拿到子组件实例。// 如果是普通元素,ref指向DOM元素;若是vue组件,则指向vue实例
eventBus、vuex等状态管理库
eventBus适合小项目的中心状态管理, this.$bus.emit()、 this.$bus.on()、this.$bus.off()
eventBus只做了状态变化后的联动处理,状态变化前的异步过程管理未支持。当项目较大时,容易混乱。vuex等状态管理库对状态变化前后都做了支持[3]。
localStorage、sessionStorage、indexDB、$route.query||params
它们也可以拿来实现组件通讯。
localStorage、sessionStorage、indexDB特点:持久化存储,配合JSON.stringify()/JSON.parse()使用;
$attrs/$listeners
单根节点组件会存在$attrs继承透传,多根节点没有自动的attribute透传行为[6]。
props逐级透传问题为什么使用provide/inject而非$attrs透传
- provide既可以传递属性,也可以传递方法;$atrrs只能传递属性,$listener传递方法,但$listener在vue3中移除
- $attrs有局限性:多根节点无法自动透传;被"消费"后无法继续向下传递。
小结
父子组件通讯适用props/$emit、$children/root)、refs/ref;
兄弟组件通讯可以父组件作为中间人;
祖孙组件通讯推荐provide/inject、$attrs/$listeners
全局中心通信推荐eventBus、vuex等状态管理库
推荐文章
参考文献
[1] 依赖注入
[2] 通信
[6] 透传 Attributes