4

vue组件通信方式很多同学会说我知道,这个简单,props传值,$emit回传,再不行就vuex。但实际上vue组件通信远远不止这些,并不是层级一多就要用vuex,一个项目就要隔多级传几个静态参数,你说我用vuex,我想这就是杀鸡用了宰牛刀,今天就来说一下具体有多少种方式,并且如何应用。

组件通信方式列举

组件通信常用方式

1、props/$emit。
2、event。
3、vuex。

自定义事件
1.边界情况

4、$parent
5、$root
6、$children
7、$refs
8、provide/inject

2.非prop特性

9、$attrs
10、$listeners

组件通信的应用

1.props/$emit
props传值非常简单,这个是最最常用的,我简单写下例子。

父组件给子组件传值

// parent 组件
<Parent msg="Welcome to vue props"/>

// child里面通过props获取msg
props: { msg: String } 

子组件传值给父组件,使用$emit

// child里面调用$emit, 第一个参数是方法名,后面都是参数
this.$emit('add', good) 

// parent,$emit会触发父组件add方法
<Parent @add="parentAdd($event)" />

2.event事件总线
前面说到的props和/$emit父子组件通信,他们存在引入与被引入的关系,如果不存在这种关系我们该怎么办呢?
这时我们常常会用到事件总线或者vuex的方式。

首先在main.js文件中通过vue原型属性初始化EventBus,
这种方式初始化的是一个全局事件总线。

import Vue from 'vue'
import App from './App.vue'

// 事件总线
Vue.prototype.$bus = new Vue()

new Vue({
  render: h => h(App),
}).$mount('#app')

在组件1中发送信息

// 利用事件总线发送事件
this.$bus.$emit('event-from-component1', 'some msg from component1')

在组件2中监听接受信息

this.$bus.$on('event-from-component1', msg => {
    console.log('component2:', msg);
});

这时只要在组件1中触发$bus.$emit的方法,组件2中$bus.$on方法就会调用,控制台就会输出:image.png

3.vuex

创建唯一的全局数据管理者store,通过它管理数据并通知组件状态变更。
vuex的强大这里就不赘述了,vuex内容比较多也不是本文的主题,这里就不细讲了,不熟悉的同学先去看下官网:https://vuex.vuejs.org/zh/guide

4.$parent
兄弟组件直接可以通过共同的祖先搭桥联通,$parent和$root都可以做到。

// brother1中发出方法
this.$parent.$emit('event-from-brother1', 'some msg from brother1')`

// brother2中接收方法
this.$parent.$on('event-from-brother1', msg => {
    console.log('brother2:', msg);
});

这时触发brother1中的方法,控制台就会显示:image.png

这是兄弟组件通信的方法,我们也可以通过$parent从子组件调用父组件的方法。

// parent里面methods定义了一个方法
methods: {
      fatherMethod() {
        console.log('我是你爹');
      }
    }
    
// children子组件里面调用父组件方法
this.$parent.fatherMethod()

当$parent.fatherMethod()方法在子组件被调用控制台便会打出:我是你爹

5.$root

$root和上面parent类似,这里就不赘述,具体请移步官网。

6.$children

父组件可以通过$children访问子组件实现父子通信,但是父组件可能含有多个子组件,所以要区分开

this.$children[index].xx = 'xxx'
 

但是有一点需要注意$children实际上不能保证子元素的顺序,也不是响应式的。
因为$children是根据你页面加载组件的顺序去确定子组件在 $children数组中的顺序。
如果A组件在B组件先加载,那么A组件的下标就是0,B组件的下标就是1。
如果有动态组件很容易出错,所以我们并不建议使用。
然而我们常用的$refs就可以解决这个问题。

7.$refs
回去节点引用,也就是获取dom

// dom中引入
<div ref="tx" /> 

// 获取上面div的dom从而操作
this.$refs.tx 

在父组件中通过ref调用子组件的方法,这里就不会有$children的顺序问题了,因为ref是一一对应的。

// 父组件
<Child2 ref="child2" msg="some message"></Child2>

// 子组件
methods: {
  sendToChild1() {
    console.log('我是父组件使用ref调用的方法')
  }
},

// 在父组件中调用子组件方法sendToChild1
`this.$refs.child2.sendToChild1()`

8.provide/inject
能够很好的跨层级通信。官网也做比较详细的说明:https://cn.vuejs.org/v2/api/#...
这个方法其实也挺好用的,但是很多同学并没有用过,可能都不是很清楚。
下面我们来具体说一下:

// 祖辈组件中提供了一个变量,这时我们使用provide方法注入
provide() {
  return {
    father: 'father'
  }
},
// 这时我们需要在某个后代元素中获取这个father变量
// 注入之后我们就可以在该后代组件中使用变量father了
inject: ['father']

// inject另外一种写法
// 这时我们需要对变量重命名,同时可以设置默认值
inject: {
  bar1: {
    from: 'father',
    default: 'barrrrrrrr'
  }
}, 

我们也可以把注入值放入我们该后代元素的data中去使用,provide/inject基本用法就是这样的。

9.$attrs
$attrs包含了父作用域中不作为 prop 被识别 (且获取) 的特性绑定 ( class 和 style 除外)。
当一个组件没有 声明任何 prop 时,这里会包含所有父作用域的绑定 ( class 和 style 除外),并且可以通过 v- bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。

// 爷爷组件中给父亲组件注入信息
<Parent msg="msg" />

// 父亲组件,我们需要在父亲组件中绑定$attr以便于孙子组件获取信息
<Children v-bind="$attrs" />

// 孙子组件:在props中没有声明msg,这时子组件依然能够收到信息
<div> {{$attrs.msg}}</div>

这时孙子组件就可以获取msg的信息了,这里其实都是跨层级通信的。
10.$listeners
如果我们需要从孙子组件调用爷爷组件的方法,实现跨层级通信的话,可以使用到$listeners。

// 爷爷组件
<Parent msg="msg" @foo="onFoo"/>

// 爷爷组件methods设置方法
onFoo() {
    console.log('msg from Children');
}

// 父亲组件,绑定$listeners
<Children v-bind="$attrs" v-on="$listeners" />

// 孙子组件:调用foo方法
this.$emit('foo')

以上内容只是本人的学习总结,紧供参考。


西若枫
20 声望5 粉丝