我面试的时候通常都会将vue组件的通信作为一个非常基础的题来考察面试者对vue的了解程度。面试者通常能够回答上prop、emit和vuex,其他方式通常很少有人了解,今天简单的做一个梳理。

概述

组件通信有以下几种场景

  1. 父组件-\>子组件
  2. 子组件-\>父组件
  3. 祖先组件与子组件间的数据传递
  4. 兄弟组件间传递及其他数据共享

父组件-\>子组件

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 是状态管理工具,实现了项目状态的集中式管理

2. localstorage

3. 路由参数

Last modification:July 6, 2021
如果觉得我的文章对你有用,请随意赞赏