Vue组件之间的通信方式的总结

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

今天我们就来总结下。

vue中组件间的通信方式

  1. props / $emit
    这是我们比较熟悉的方式,主要是父子组件之间的传递方式,父传子使用props,子传父使用 $emit,直接上代码:

父组件传子组件

首先在父组件的子组件标签中绑定一个自定义的属性

<user-detail :age="age" />
    
export default {
    components: {
        MyAge
    }
    ......
}

在子组件中使用props进行接收,接收的形式可以是数组,也可以是对象
数组方式:

export default {
    props: ['age']
}

对象方式:

export default {
    props: {
		'age': String
    }
}

注意事项: props用对象的方式进行接收时,要写出属性对应的数据类型,可以起验证作用。如上面的age对应String类型,如果父组件传过来age的值数据类型不为String,那么就会报错。

子组件传父组件
子组件绑定一个事件,通过 this.$emit() 来触发

// 子组件
<button @click="changeAge">改变父组件的age</button>export default {
    methods: {
        //子组件的事件
        changeAge: function() {
            this.$emit('ageChange', '18') // 触发父组件中ageChange事件并传参18
            // 注:此处事件名称与父组件中绑定的事件名称要一致
        }
    }
}
// 父组件
<child @ageChange="ageChange"></child>
​
methods: {
    ageChange(age) {  // age形参是子组件中传入的值18
        this.age= age
    }
}
  1. $emit / $on
    这种方法通过一个空的Vue实例作为中央事件总线EventBus(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级。当我们的项目比较大时,可以选择更好的状态管理解决方案vuex。
    用法如下:

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

import Vue from 'Vue'
export default new Vue

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

import Bus from '这里是你引入bus.js的路径' // Bus可自由更换喜欢的名字

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

Bus.$emit('click',data) 
// 这个click是一个自定义的事件名称,data就是你要传递的数据

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

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

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

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

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

beforeDestroy(){
   bus.$off('click')
}
  1. vuex

  2. $ 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" 传入内部组件

  1. provide/ inject

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

provide / inject API 主要解决了跨级组件间的通信问题,不过它的使用场景,主要是子组件获取上级组件的状态,跨级组件间建立了一种主动提供与依赖注入的关系。
举个例子:
假设有两个组件:A.vue 和 B.vue,B 是 A 的子组件

// A.vue
export default {
  provide: {
    name: '浪里行舟'
  }
}
// B.vue
export default {
  inject: ['name'],
  mounted () {
    console.log(this.name);  // 浪里行舟
  }
}
  1. $parent / $children与 ref

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

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

// component-a 子组件
export default {
  data () {
    return {
      title: 'Vue.js'
    }
  },
  methods: {
    sayHello () {
      window.alert('Hello');
    }
  }
}
// 父组件
<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

转载自bug收集微信公众号
地址:https://mp.weixin.qq.com/s/LBe3xd00FMWV5O4EDs30ig
点击跳转公众号文章地址

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值