Skip to content
本页目录

组件传值

父子组件

  • props / $emit
  • ref this.$refs.xxx 通过子组件的实例来获取子组件数据或方法调用
  • $parent this.$parent.xxx 获取父组件数据或方法调用

兄弟组件

  • $parent
  • $root
  • eventbus
  • vuex

跨层级关系

  • $attrs / listeners
  • vuex
  • provide / inject
  • $root

1. $attrs$listeners v2.4版本新增

解决跨组件通信问题,其它方式都有缺陷:

  • props 需要一层层传递,冗余难维护
  • vuex 适合大些的场景
  • provide / inject 自身有缺陷
  • eventBus 可读性低,可维护下也不太好

目前用到的场景是最三方组件的再次封装,能直接继承三方组件的所有属性与方法

2. $attrs

包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。
它有个布尔值的 inheritAttrs 属性,用于控制是否启用 attribute ,默认为开启。

HTML
<!-- 简单来说,在父->子->孙结构的组件中,子组件的这样写法 -->
<!-- 父->孙组件就能直接使用 props 与 $emit 传递数据与接受事件了 -->
<dom-child v-bind="$attrs" v-on="$listeners" />
<!-- 简单来说,在父->子->孙结构的组件中,子组件的这样写法 -->
<!-- 父->孙组件就能直接使用 props 与 $emit 传递数据与接受事件了 -->
<dom-child v-bind="$attrs" v-on="$listeners" />

3. $listeners

包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。

示例1:

HTML
<!-- 父组件 -->
<demo-parent name="zhangsan" />

<!-- 子组件 this.$attrs.name -->
<div>{{ $attrs.name }}</div>
<!-- 父组件 -->
<demo-parent name="zhangsan" />

<!-- 子组件 this.$attrs.name -->
<div>{{ $attrs.name }}</div>

4. provide / inject

可以给组件所有后代传递数据,最大问题是绑定不是响应式的,同时多人维护时也不够透明,但是在实现通用组件时还是很好用的。

举个例子:element-ui 中,组件会有个 size 属性,比如表单 el-formsize 属性会影响其所有表单内的组件 size,我们可以使用 provideinject 实现 size 的传递,即使中级隔着非表单组件。

5. eventBus

兄弟组件间通信,目前使用来看,代码维护与可读性都不好

  • 创建一个中央事件总线EventBus
  • 兄弟组件通过$emit触发自定义事件,$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的功能
// 创建一个中央时间总线类  
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的功能

child1.vue

JS
this.$bus.$emit('foo')
this.$bus.$emit('foo')

child2.vue

JS
this.$bus.$on('foo', this.handle)
this.$bus.$on('foo', this.handle)