Vue2 组件间的交互

前言

vue 组件之间的交互必不可少,不同的场景我们可以使用不同的实现方式,本文主要是分享下组件之间的多种数年交互方式。

父子组件

对于这种场景我们可以通过 props 向子组件传递数据,子组件可以通过事件 this.$emit() 的方式向父组件传递数据,这种方式很常用。

获取子组件的实例,可以通过在父组件中给子组件添加 ref="child" 属性,然后通过 this.$refs['child'] 进行获取。或者可以通过 this.$children 来获取,不过它是一个由父组件中引用了所有子组件的实例组成的数组。所有需要通过下标来获取对应的子实例。

获取父组件实例可以通过 this.$parent 。

多组件嵌套

比如有组件 A 、B、C,它们依次嵌套。我们想做的就是组件 C 需要接收组件 A 传给组件 B 的所有 props 属性,以及组件 A 想监听组件 C 中的所有事件。

笨方:

场景1:

按上面的来,先把所有的属性通过 props 传给组件 B ,然后组件 B 再通过 props 属性传给组件 C 。如果属性少还好,属性多的话就有点难受了。

场景2:同样的如果组件 C 想给组件 A 传数据,可以通过事件 this.$emit() 的方式一层一层往上传。

妙方:

场景1:

我们就可以通过 B 组件实例的 $attrs 来获取组件 A 传给组件 B 的所有 props 属性,然后再把这个属性通过 v-bind='$attrs' 绑定到组件 C 上就可以了。组件 C 就可以获取到所有的 props 属性了(注意:C 组件中的 props 需要声明 A 中传过来的所有属性,并且如果组件 B 中有在 props 中定义一些同名的属性,那么这些属性都不会传给组件 C,相当于被拦截了)

场景2:

跟上面的正好相反,也就是组件 A 需要监听组件 C 中所有的事件,而它们之间还有一个组件 B,比如:组件 C 中有一个输入框,组件 A 想监听输入框的所有事件,此时我们就可以在 input 通过 v-on='$listeners' 把 input 所有的事件都发出,然后在组件 B 中作同样的操作,组件 A 就可以监听到 组件 C 中 input 的所有事件了。下面是一个精简后的示例

<!-- 组件A -->
<div class="component-a">
  <component-b :show="isShow" title="vue.js" @input="inputHandler"></component-b>
</div>
<!-- 组件B -->
<div class="component-b">
  <component-b v-bind="$attrs" v-on="$listeners"></component-b>
</div>
<!-- 组件C -->
<div class="component-c">
  <input v-on="$listeners" type="text">
</div>

如果组件 B 的 props 中声明了一个 show 属性那么传递到组件 C 的属性就只剩下 title 属性了。

可以把上面所说实例的 $attrs 和 $listeners 看作是批处理属性

超组件嵌套

这里所说的超组件嵌套是指组件嵌套的深度超过了三层。此时用上面的方法也觉得是体力活,但不要担心,我们还有针对这种非一般的场景的解决方案。

假设组件 C 与 组件 A 之间经过了很多层组件,此时组件 C 获取组件 A 实例可以通过 provide/inject 来实现:

// 父组件添加 provide 属性
provide: {
  parent: this
},

parent 相当于 key ,this 相当于值

在 C 组件中通过 inject 来接收指定的 key

inject: ['parent']

然后就可以在组件 C 中通过 this.parent 来获取到组件 A 的实例了。思想再放开点如果如果我们给 parent 赋的值不是 this ,而是给组件 C 传递一些参数,就可以实现跨组件传参了。

关于 provide/inject 的更多资料可阅读:https://cn.vuejs.org/v2/api/#provide-inject

但针对这超组件嵌套需要把事件从底层往外传的话,vue 官方就没有为我们实现了。但我们可以通过事件总线自已实现。通过一个管理中心来统一处理数据或者事件。关于事件总线可阅读:https://www.jianshu.com/p/4fa3bf211785

关于数据的传递及交互我们还可以通过状态管理 vuex 来实现各组件之间的通信,这种方式就方便多了,不管是父子组件、兄弟组件、还是跨组件通信,都很轻松的解决。并且在组件中获取数据的方式一样。通过形如:this.$store.state.user 来获取。对于 vuex 的更多资料可以阅读:https://vuex.vuejs.org/zh/,这种方式其实跟事件总线异曲同工之妙。