专栏首页Modeng的专栏Vue案例引发的「嵌套组件」通信的简单方式

Vue案例引发的「嵌套组件」通信的简单方式

我们都知道 Vue 是采用组件化开发的模式,组件化的优势在于相对独立,易于维护,可复用。你可以把项目看成许多组件的组合而成。

既然项目中存在很多的组件,而且又是相对独立的,但组件间肯定是存在数据的传递交互。Vue中给我提供比较多的方式去进行组件间的交互通信。

这篇文章不打算详尽组件之间的通信,而是说说利用 $attrs 与 $listeners 进行「嵌套组件」的通信。

可以想象一下项目中组件与组件的关系无外乎这么几种:父子,兄弟,祖孙(嵌套)。

  1. 父子组件:父组件通过 props 向下传递子组件数据,子组件通过事件向上发送父组件消息。或者也可以通过 ref 属性、$parent、$children等方法获取数据和事件。
  2. 兄弟组件:可以通过共同的父组件作为桥梁进行通讯,也可以利用全局事件 eventBus 或者比较复杂的 Vuex。

一图胜千言

通过上图,我们可以了解常见的组件通信方式。但实际的开发项目中可能并没有这么简单,最近在做项目时遇到嵌套组件的情况,比如「组件A」包含「组件B」,「组件B」包含「组件C」。

那「组件A」与「组件C」如何通信就是值得我们商榷的问题,是利用 Vuex 还是利用其他方式呢?

首先 Vuex 是优秀的状态管理工具,对于复杂而又庞大的系统而言使用 Vuex 再好不过。

但如果我们的系统相对简单,并且「组件A」与「组件C」之间只是进行简单的数据传递,似乎引入 Vuex 并不是一个好的选择,相反会带来复杂度的上升。

不过 Vue 在 2.4.0 版本添加了 2 个属性「$attrs」与「$listeners」,使用它们进行嵌套组件(祖孙)的通信是一个不错的选择,接下来我们就看看它们是什么,以及如何使用。

1.$attrs

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

2.$listeners

包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。

简单来说:$attrs 与 $listeners 是两个「对象」,$attrs 里存放的是父组件中绑定的非 Props 属性,$listeners里存放的是父组件中绑定的非原生事件。

在不明白的话看个案例

//componentA
<template>
  <div class="component-a">
    <component-b :name="name" :tag="tag" :age="age" @click.native="say" @mouseover="sing"></component-b>
  </div>
</template>
<script>
import componentB from "./ComponentB";
export default {
  name: "componentA",
  components: { componentB },
  data() {
    return {
      name: "六哥",
      tag: "帅",
      age: 18
    };
  },
  methods: {
    say() {},
    sing() {}
  }
};
</script>

//componentB
<template>
  <div class="component-b"></div>
</template>
<script>
export default {
  name: "ComponentB",
  props: {
    age: Number
  },
  mounted() {
    console.log(this.$attrs, this.$listeners);
    //{name: "六哥", tag: "帅"}, {mouseover: ƒ}
  }
};
</script>

明白这两个属性之后,我们来看看如何利用它进行祝祖孙组件之间的传递。假如有三个组件分别是「组件A」包含「组件B」,「组件B」包含「组件C」。

在上面案例的基础上,我们添加「组件C」,并对「组件B」进行改善。

//componentB
<template>
  <div class="component-b">
    <component-c v-bind="$attrs" v-on="$listeners"></component-c>
  </div>
</template>
<script>
import ComponentC from "./ComponentC";
export default {
  name: "ComponentB",
  components: { ComponentC }
};
</script>

//componentC
<template>
  <div class="component-c"></div>
</template>
<script>
export default {
  name: "ComponentC",
  mounted() {
    console.log(this.$attrs, this.$listeners);
    //{name: "六哥", tag: "帅", age: 18} {mouseover: ƒ}
  }
};
</script>

可以看到我们利用「$attrs」与「$listeners」在不引入额外的工具或者全局属性,就可以实现从「组件A」到「组件C」之间的数据通信。如果有相同场景的小伙伴,赶紧用起来吧。

另外一点,这里需要注意我们使用了非 Props 特性,Vue 中组件如果接受非 Props 属性的时候,会把属性渲染到 HTML 的原生标签上。

例如:

<component-b :name="name" :tag="tag"></component-b>

渲染后的结果会是

<div class="component-b" name="六哥" tag="帅"></div>

显然这不是我们想要的,我们的原生标签不需要 「name」与 「tag」这两个属性。那如何避免的呢?很简单,你可以在组件的选项中设置 inheritAttrs: false。

<script>
import ComponentC from "./ComponentC";
export default {
  inheritAttrs: false,
  name: "ComponentB",
  components: { ComponentC }
};
</script>

以上就是我们今天要说的 「$attrs」与「$listeners」,欢迎小伙伴们留言交流。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Vue2.5源码阅读笔记02—虚拟DOM的创建与渲染

    Vue是数据驱动的MVVM框架,视图是由数据驱动生成的,因此对视图的修改不是通过操作 DOM,而是通过修改数据,相比传统使用jQuery的前端开发,能够大大简化...

    csxiaoyao
  • vue封装带提示框的单选/多选文本框组件

    在web开发中,经常会遇到公共模块复用的问题,例如页头、页脚、导航条等,传统的后端视图引擎如smarty、服务器配置SSI、或是纯前端的嵌套iframe、js请...

    csxiaoyao
  • Vue2.5源码阅读笔记01—代码结构与初始化

    Vue作为当下最流行的渐进式的js框架,其渐进式的思想、虚拟DOM的运用、组件化的开发模式、响应式数据侦听原理值得开发者进行探索学习,其中运用的代码组织的技巧,...

    csxiaoyao
  • MongoDB MongoVue 客户端

    MongoVue,是一款MongoDB的客户端工具,1.0版本的开始收费了,本文最后提供免费破解版v1.5.3。

    阳光岛主
  • 18.5.21日报

    1,跟进https://www.iviewui.com点击链接无反应的问题。原因猜测还是和messageport实现有关。

    龙泉寺扫地僧
  • Vue项目错误汇总

    城市中的游牧民族
  • 梳理vue双向绑定的实现原理

    Vue 采用数据劫持结合发布者-订阅者模式的方式来实现数据的响应式,通过Object.defineProperty来劫持数据的setter,getter,在数据...

    周陆军
  • 18.4.21日报

    1,跟进一处woff2字体显示不了的问题。原因是获取的字符宽度为0,但在chromium.bb里也是0,暂时放弃跟进

    龙泉寺扫地僧
  • Vue学习笔记之Vue的对象单体模式

    Jetpropelledsnake21
  • 前端面试题汇总

    (1) vue.js 兄弟组件通信 生命周期 vue router vuex 原理 (2) angular (3) react ...

    城市中的游牧民族

扫码关注云+社区

领取腾讯云代金券