组件间通信的概念
在介绍方法之前,我们先来了解下什么是组件间通信。
我们都知道,组件是Vue的核心功能之一。每个Vue中的.Vue 文件都可以把它看做一个组件。
而通信是指发送者通过某种媒体、某种格式将传递信息传递给收集者来达到某种目的。
从广义上来说,任何信息的交通都是组件间通信 ,即组件(.Vue)通过某种方式来传递信息以达到某个目的。来看个例子,我们在使用UI框架中的table
组件,可能会往这个组件中传入一些数据,这就形成了组件间的通信。
通信种类
组件间的通信可以分成四个类型:
- 父子组件间的通信。
- 兄弟组件间的通信。
- 祖孙和后代组件间的通信。
- 非关系组件间的通信。
组件间通信的方案
1.props
props只能从父组件传递给子组件,也就是所谓的单向传递。通过在子组件设置props属性,来定义从父组件那接收的参数。而且父组件可以通过子组件标签来传递值。
Father
<Children name="jack" age=18 />
Children
props:{
// 字符串形式
name:String // 接收的类型参数
// 对象形式
age:{
type:Number, // 接收的类型为数值
defaule:18, // 默认值为18
require:true // age属性必须传递
}
}
2.$emit
$emit
是子组件向父组件传递数据的方法。
$emit
之所以可以让子组件向父组件传递参数,是因为父组件在子组件中利用v-on
来监听函数并接收参数。
子组件通过$emit
触发自定义事件,$emit
的第二个参数是传递的数值。
Father
<Children @add="cartAdd($event)" />
Children
this.$emit('add', good)
3.ref
ref想必都很熟悉,父组件可以通过设置子组件ref
来获取数据。如果在普通的DOM元素上使用,则指向DOM元素;在子组件上使用则指向组件实例,可以通过实例来直接调用组件的方法或访问数据。
Father
<Children ref="foo" />
this.$refs.foo // 获取子组件实例,通过子组件实例我们就能拿到对应的数据
4.EventBus
EventBus用于兄弟组件之间传值,首先要创建一个中央事件总线,兄弟组件则是通过$emit
触发自定义事件,另一个兄弟组件是通过$on
来监听自定义事件。
js
// 创建一个中央时间总线类
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.prototype.$bus = new Vue() // Vue已经实现了Bus的功能
Children1
this.$bus.$emit('foo')
Children2
this.$bus.$on('foo', this.handle)
5.parent或$root
通过共同的祖先$parent
或$root
搭建通信桥连。
Children1
this.$parent.on('add',this.add)
Children2
this.$parent.emit('add')
6.attrs和$listeners
$attrs
和$listeners
是Vue中的两个属性,$attrs
包含父作用域中传递给子组件的所有属性(除了class
、style
和被声明为props
的属性)。
它是一个对象,包含剩下所有的HTML特性和事件监听器。而且还可以通过v-bind=$attrs
传入内部组件。
js
// child:并未在props中声明foo
<p>{{$attrs.foo}}</p>
// parent
<HelloWorld foo="foo"/>
js
// 给Grandson隔代传值,communication/index.vue
<Child2 msg="lalala" @some-event="onSomeEvent"></Child2>
// Child2做展开
<Grandson v-bind="$attrs" v-on="$listeners"></Grandson>
// Grandson使⽤
<div @click="$emit('some-event', 'msg from grandson')">
{{msg}}
</div>
7.provide和inject
provide
和inject
是Vue中在组件中进行依赖注入的两个选项它们允许祖先组件向子孙组件传递数据或资源。这个方法尤其是在嵌套层级较深时特别适合,如果使用props
和$emit
会难以维护。
现在祖先组件定义provide
属性,返回传递的值;再到子孙组件通过inject
接受组件传递过来的值。
Father
provide(){
return {
foo:'foo'
}
Children
inject:['foo']
8.vuex
vuex是Vue自身的状态管理模式和库。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方法发生变化。
重要概念
- State(状态):存储应用层的状态,任何状态更新都应该遵循Vuex的规定流程。
- Getter:类似于Vue中的计算属性,可以从
State
中派生出一些状态;可以接受state作为第一个参数,也可以接受其他getters作为第二个参数。 - Mutation:想要更改store状态的唯一方法是提交mutation。每个mutation都带有一个type(事件类型)和handler(回调函数)。
注意:Mutation必须是同步函数。
- Action:与Mutation相似但略有不同,Action提交的是Mutation而不是直接改变状态,而且Action可以包含任意的异步操作。Action要通过
satore.dispatch
来触发。 - Module:Vuex允许我们将
store
切割成模块(Module)。每个模块都拥有自己的state、mutation、action、getter和嵌套子模块------自上而下进行同样方式的分割。
总结
- 父子关系的组件数据传递选择
props
与$emit
进行传递,也可选择ref
。 - 兄弟关系的组件数据传递可选择
$bus
,其次可以选择$parent
进行传递。 - 祖先与后代组件数据传递可选择
attrs
与listeners
或者Provide
与Inject
。 - 复杂关系的组件数据传递可以通过
vuex
存放共享的变量。