组件通信是现在网页应用当中常见的需求,根据通信的主体不同可以分为以下几个大类:

  1. 父子组件之间通信
  2. 祖先组件与后代组件(不限层级)的通信
  3. 任意组件通信

下面根据上面这三个大类对Vue的组件通信进行总结:

父子通信

props

用于父组件向子组件传递数据

  1. // child
  2. {
  3. props: {
  4. name: String
  5. }
  6. }
  7. <div>{{name}}</div>
  8. // parent
  9. <child name="Bill" />

$attrs

同样是父组件向子组件传递数据,与props相比较,$attrs的属性无需声明即可读取

  1. // child
  2. <div>{{$attrs.name}}</div>
  3. // parent
  4. <child name="Bill" />

批量传递:常见的用法还有父组件通过 v-bind="$attrs" 直接将自身的 $attrs 传递给子组件

  1. // app
  2. <parent name="Bill" height="180" weight="99"/>
  3. // parent
  4. <div>
  5. <child v-bind="$attrs" />
  6. </div>

$listeners

父组件向子组件传递的事件,包括原生事件和自定义事件

  1. // parent
  2. <div><child @click="handleClick" @custom="handleCustom"/></div>
  3. // child
  4. this.$listeners.click // function handleClick

同样$listeners也能通过上面的方式批量传递给下一层的组件

  1. // app
  2. <parent @custom="handleCustom"/>
  3. // parent
  4. <div>
  5. <child v-on="$listeners" />
  6. </div>

$children

父组件访问子组件的内容

  1. // child
  2. {
  3. data() {
  4. return {value: 1}
  5. }
  6. }
  7. // parent
  8. this.$children[0].value

$refs

父组件获取子组件的DOM节点引用

  1. // child
  2. <div>child</div>
  3. // parent
  4. <div><child ref="c"/></div>
  5. this.$refs.c

自定义事件

用于子组件向父组件传递数据

  1. // child
  2. {
  3. onChange() {
  4. this.$emit('change', this.value)
  5. }
  6. }
  7. // parent
  8. <child @change="handleChange(e)"/>

祖先后代通信

provide/inject

祖先向后代传递数据,祖先组件声明provide的值,后代通过inject获取到来自祖先的值

  1. // ancestor
  2. {
  3. provide: {
  4. name: 'Bill'
  5. }
  6. }
  7. // descendant
  8. {
  9. inject: ['name']
  10. }

缺点是不能实现数据响应式,只能传递静态的数据

$root

后代访问根实例

全局通信

EventBus事件总线

这个事件总线可以是自己实现,也可以直接使用vue实例。使用Vue实例作为事件总线更为强大,因为它不仅能实现事件监听与派发,还能实现全局的数据响应式。

手动实现版本:

  1. class Bus {
  2. constructor() {
  3. this.callbacks = {}
  4. }
  5. $on(type, handler) {
  6. this.callbacks[type] = this.callbacks[type] || []
  7. this.callbacks[type].push(handler)
  8. }
  9. $off(type, handler) {
  10. if (this.callbacks[type]) {
  11. this.callbacks[type] = this.callbacks.filter(fn => fn !== handler)
  12. }
  13. }
  14. $emit(type, ...args) {
  15. this.callbacks[type] && this.callbacks[type].forEach(handler => handler(...args))
  16. }
  17. }
  18. Vue.prototype.$bus = new Bus()

vue版本

  1. Vue.prototype.$bus = new Vue()

Vuex

创建全局的store,通过它来获取数据与处理数据,另开一篇文章详细说