我面试的时候通常都会将vue组件的通信作为一个非常基础的题来考察面试者对vue的了解程度。面试者通常能够回答上prop、emit和vuex,其他方式通常很少有人了解,今天简单的做一个梳理。
概述
组件通信有以下几种场景
- 父组件-\>子组件
- 子组件-\>父组件
- 祖先组件与子组件间的数据传递
- 兄弟组件间传递及其他数据共享
父组件-\>子组件
1.Prop
props是响应式的,可以做数据绑定
2.$ref
ref 被用来给元素或子组件注册引用信息。就是绑定在普通元素上,则获取到这个DOM元素,若是绑定在组件上,则获取到的是这个组件的Vue实例vm。尽量避免使用
// 父组件添加ref
<component-children ref="child"></component-children>
// 利用this.$refs.child调用子组件数据和方法
this.$refs.child.data
3. $children
访问子组件的实例vm,尽量避免使用
子组件-\>父组件
1. $emit
在子组件中$emit自定义事件,在父组件中监听这个事件并在回调中写相关逻辑
// 父组件监听子组件定义的事件
<component-children @emitValue='emitValue'></component-children>
// 子组件需要返回数据时执行,并可以传递数据
this.$emit('emitValue', data)
利用$emit我们可以实现EventBus、如果是一些简单的项目的状态管理,没必要用上vuex,我们就可以用provide 和 inject(后面会简单阐述)或者eventbus来替代vuex。EventBus
通过新建一个 Vue
事件 bus
对象,然后通过 bus.$emit
触发事件,bus.$on
监听触发的事件
//定义中央事件总线
const EventBus = new Vue();
// 将中央事件总线赋值到 Vue.prototype 上,这样所有组件都能访问到了
Vue.prototype.$EventBus = EventBus;
const app = new Vue({
el: '#app',
template: `
<div>
<A />
<B />
</div>
`
});
// 组件 A
Vue.component('A', {
template: `
<div>
<p>this is A component!</p>
<input type="text" v-model="mymessage" @input="passData(mymessage)">
</div>
`,
data() {
return {
mymessage: 'hello brother1'
}
},
methods: {
passData(val) {
//触发全局事件globalEvent
this.$EventBus.$emit('globalEvent', val)
}
}
});
// 组件 B
Vue.component('B', {
template:`
<div>
<p>this is B component!</p>
<p>组件A 传递过来的数据:{{brothermessage}}</p>
</div>
`,
data() {
return {
mymessage: 'hello brother2',
brothermessage: ''
}
},
mounted() {
//绑定全局事件globalEvent
this.$EventBus.$on('globalEvent', (val) => {
this.brothermessage = val;
});
}
});
2. .sync修饰符
.sync实际是一个语法糖
// 下面两个父组件写法等价
<text-document
v-bind:title="doc.title"
v-on:update:title="doc.title = $event"
></text-document>
<text-document v-bind:title.sync="doc.title"></text-document>
// 子组件emit值更新事件
this.$emit('update:title', newTitle)
3. $parent
访问父组件的实例vm,尽量避免使用
祖先组件与子组件间的数据传递
1. provide/inject
这个是 Vue.js 2.2.0 版本后新增的 API,文档上有以下功能描述
这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。如果你熟悉 React,这与 React 的上下文特性很相似。
provide 和 inject 主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。
示例:
// 父级组件提供 'foo'
var Provider = {
provide: {
foo: 'bar'
},
// ...
}
// 子组件注入 'foo'
var Child = {
inject: ['foo'],
created () {
console.log(this.foo) // => "bar"
}
// ...
}
需要注意的点是:
- provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的。
- 一旦注入了某个数据,比如上面示例中的 foo,那这个组件中就不能再声明 foo 这个数据了,因为它已经被父级占有。
2. $attrs/$listeners
$attrs
包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。$listeners
包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。
兄弟组件间传递及其他数据共享
1. vuex
Vuex 是状态管理工具,实现了项目状态的集中式管理
One comment
作者的布局谋篇匠心独运,让读者在阅读中享受到了思维的乐趣。