vue中组件间通信方式的总结

2022-07-22 14:25:27 浏览数 (2)

面试中,经常会问到vue中组件间的通信方式有哪些?

今天我们就来总结下。

vue中组件间的通信方式

方法一、props/$emit

这是我们比较熟悉的方式,主要是父子组件之间的传递方式,父传子使用props,子传父使用$emit.

此方法经常使用,就不罗列代码了

方法二、$emit/$on

这种方法通过一个空的Vue实例作为中央事件总线EventBus(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。当我们的项目比较大时,可以选择更好的状态管理解决方案vuex。

用法如下:

第一步:项目中创建一个js文件(我通常给它取个名字为bus.js),引入vue,创建一个vue实例,导出这个实例,代码如下(一共就两行):

代码语言:javascript复制
import Vue from 'Vue'
export default new Vue

第二步:在两个需要通信的两个组件中分别引入这个bus.js

代码语言:javascript复制
import Bus from '这里是你引入bus.js的路径' // Bus可自由更换喜欢的名字

第三步:传递数据的组件里通过vue实例方法$emit发送事件名称和需要传递的数据。(发送数据组件)

代码语言:javascript复制
Bus.$emit('click',data) 
// 这个click是一个自定义的事件名称,data就是你要传递的数据

第四步:被传递数据的组件内通过vue实例方法$on监听到事件和接受到数据。(接收数据的组件)这里通常挂载监听在vue生命周期created和mounted当中的一个,具体使用场景需要具体的分析,这里不说这个。

代码语言:javascript复制
Bus.$on('click',target => {
  console.log(target)  
  // 注意:发送和监听的事件名称必须一致,target就是获取的数据,可以不写target。只要你喜欢叫什么都可以(当然了,这一定要符合形参变量的命名规范)
})

通过以上的四步其实就已经实现了最简单的eventbus的实际应用了。

但是到这儿后,一定要注意一个最容易忽视,又必然不能忘记的东西,那就是清除事件总线eventBus.不手动清除,它是一直会存在的

第五步:在vue生命周期beforeDestroy或者destroyed中用vue实例的$off方法清除eventBus

代码语言:javascript复制
beforeDestroy(){
   bus.$off('click')
}

方法三、vuex (自己查阅具体方法)

方法四、$attrs/$listeners(自己查阅具体方法)

多级组件嵌套需要传递数据时,通常使用的方法是通过vuex。但如果仅仅是传递数据,而不做中间处理,使用 vuex 处理,未免有点大材小用。为此Vue2.4 版本提供了另一种方法----$attrs/$listeners

$attrs:包含了父作用域中不被 prop 所识别 (且获取) 的特性绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件。通常配合 interitAttrs 选项一起使用。

$listeners:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件

方法五、provide/inject

Vue2.2.0新增API,这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。一言而蔽之:祖先组件中通过provider来提供变量,然后在子孙组件中通过inject来注入变量。

provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。

举个例子

假设有两个组件:A.vue 和 B.vue,B 是 A 的子组件

// A.vue

代码语言:javascript复制
export default {
  provide: {
    name: '浪里行舟'
  }
}

// B.vue

代码语言:javascript复制
export default {
  inject: ['name'],
  mounted () {
    console.log(this.name);  // 浪里行舟
  }
}

方法六、$parent / $children与 ref

ref:如果在普通的 DOM 元素上使用,引用指向的就是 DOM 元素;如果用在子组件上,引用就指向组件实例

$parent / $children:访问父 / 子实例

需要注意的是:这两种都是直接得到组件实例,使用后可以直接调用组件的方法或访问数据。我们先来看个用 ref来访问组件的例子:

// component-a 子组件

代码语言:javascript复制
export default {
  data () {
    return {
      title: 'Vue.js'
    }
  },
  methods: {
    sayHello () {
      window.alert('Hello');
    }
  }
}

// 父组件

代码语言:javascript复制
<template>
  <component-a ref="comA"></component-a>
</template>
<script>
  export default {
    mounted () {
      const comA = this.$refs.comA;
      console.log(comA.title);  // Vue.js
      comA.sayHello();  // 弹窗
    }
  }
</script>

不过,这两种方法的弊端是,无法在跨级或兄弟间通信。

总结

常见使用场景可以分为三类:

父子通信:

父向子传递数据是通过 props,子向父是通过 events($emit);通过父链 / 子链也可以通信($parent / $children);ref 也可以访问组件实例;provide / inject API;$attrs/$listeners

兄弟通信:

Bus;Vuex

跨级通信:

Bus;Vuex;provide / inject API、 $attrs/$listeners

0 人点赞