Vue案例引起的「嵌套組件」通訊的簡單方式

咱們都知道 Vue 是採用組件化開發的模式,組件化的優點在於相對獨立,易於維護,可複用。你能夠把項目當作許多組件的組合而成。bash

既然項目中存在不少的組件,並且又是相對獨立的,但組件間確定是存在數據的傳遞交互。Vue中給我提供比較多的方式去進行組件間的交互通訊。工具

這篇文章不打算詳盡組件之間的通訊,而是說說利用 $attrs 與 $listeners 進行「嵌套組件」的通訊。組件化

能夠想象一下項目中組件與組件的關係無外乎這麼幾種:父子,兄弟,祖孫(嵌套)。ui

  1. 父子組件:父組件經過 props 向下傳遞子組件數據,子組件經過事件向上發送父組件消息。或者也能夠經過 ref 屬性、$parent、$children等方法獲取數據和事件。
  2. 兄弟組件:能夠經過共同的父組件做爲橋樑進行通信,也能夠利用全局事件 eventBus 或者比較複雜的 Vuex。

一圖勝千言this

經過上圖,咱們能夠了解常見的組件通訊方式。但實際的開發項目中可能並無這麼簡單,最近在作項目時遇到嵌套組件的狀況,好比「組件A」包含「組件B」,「組件B」包含「組件C」。spa

那「組件A」與「組件C」如何通訊就是值得咱們商榷的問題,是利用 Vuex 仍是利用其餘方式呢?code

首先 Vuex 是優秀的狀態管理工具,對於複雜而又龐大的系統而言使用 Vuex 再好不過。component

但若是咱們的系統相對簡單,而且「組件A」與「組件C」之間只是進行簡單的數據傳遞,彷佛引入 Vuex 並非一個好的選擇,相反會帶來複雜度的上升。cdn

不過 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」,歡迎小夥伴們留言交流,若是以爲本文不錯,記得點贊哦,碼字不容易。

相關文章
相關標籤/搜索