2022-01-28【技術(shù)】Vue使用$attrs與$listeners實(shí)現(xiàn)多層嵌套傳遞

現(xiàn)有3個(gè)嵌套組件脚曾,A->B东且,B->C。 現(xiàn)在我么需要在A中對(duì)C的props賦值本讥,監(jiān)聽C的emit事件
A組件與C組件通信珊泳,我們有多少種解決方案?

1拷沸、我們使用vuex來進(jìn)行數(shù)據(jù)管理色查,依賴于vuex我們可以一次改變,任何一個(gè)組件中都能獲取撞芍。但是如果多個(gè)組件共享狀態(tài)比較少综慎,使用vuex過于麻煩和難以維護(hù)。element-ui中大量采用此方法勤庐。
2示惊、自定義vue bus事件總線,原理類似vuex愉镰,使用特別簡(jiǎn)單米罚。bus適合碰到組件跨級(jí)兄弟組件等無明顯依賴關(guān)系的消息傳遞,原生app開發(fā)中經(jīng)常用到丈探,但是缺點(diǎn)是bus破壞了代碼的鏈?zhǔn)秸{(diào)用录择,大量的濫用將導(dǎo)致邏輯的分散,出現(xiàn)問題后很難定位碗降,降低了代碼可讀性隘竭。
3、使用B來做中轉(zhuǎn)讼渊,A傳遞給B动看,B再給C這是最容易想到的方案爪幻,但是如果嵌套的組件過多菱皆,需要傳遞的事件和屬性較多须误,會(huì)導(dǎo)致代碼繁瑣,代碼維護(hù)困難仇轻。

對(duì)于我們這種情況京痢,3種方式都有局限性

在vue2.4中,為了解決該需求篷店,引入了attrs和listeners祭椰,新增了inheritAttrs選項(xiàng)。我們只需要在B組件中對(duì)引入的C組件增加下面兩個(gè)屬性即可綁定所有的屬性和事件疲陕。

<C v-bind="$attrs" v-on="$listeners"></C>

A組件

<template>
<div>
  <h2>組件A 數(shù)據(jù)項(xiàng):{{myData}}</h2>
  <B @changeMyData="changeMyData" :myData="myData"></B>
</div>
</template>
<script>
import B from "./B";
export default {
  data() {
    return {
      myData: "100"
    };
  },
  components: { B },
  methods: {
    changeMyData(val) {
      this.myData = val;
    }
  }
};
</script>

B組件


<template>
  <div>
    <h3>組件B</h3>
    <C v-bind="$attrs" v-on="$listeners"></C>
  </div>
</template>
<script>
import C from "./C";
export default {
  components: { C },
};
</script>

C組件

<template>
  <div>
    <h5>組件C</h5>
    <input v-model="myc" @input="hInput" />
  </div>
</template>
<script>
export default {
  props: { myData: { String } },
  created() {
    this.myc = this.myData;  // 在組件A中傳遞過來的屬性
    console.info(this.$attrs, this.$listeners);
  },
  methods: {
    hInput() {
      this.$emit("changeMyData", this.myc); // // 在組件A中傳遞過來的事件
    }
  }
};
</script>

實(shí)際應(yīng)用
element-ui開發(fā)的后臺(tái)項(xiàng)目中吭产,大量使用到了el-table和el-pagination做分頁數(shù)據(jù)展示,所以我封裝一個(gè)自定義組件page-table


<template>
  <div class="page-table">
    <div class="wrapper">
      <el-table
          ref="elTable"
          :data="tableData">
        <slot/>
      </el-table>
      <div style="margin-top: 16px;overflow: hidden">
        <el-pagination
            class="page"
            :current-page="currentPage"
            layout="total, prev, pager, next, jumper"
            :total="total"
            @current-change="handleCurrentChange"/>
      </div>
    </div>
  </div>
</template>

但是這樣做的副作用是引用page-table的地方無法使用el-table和屬性和事件鸭轮。我們?cè)趐age-table中把所有el-table的屬性和事件都中轉(zhuǎn)一遍臣淤?有上百個(gè)呢。
只需在el-table使用的地方加上v-on="listeners"和v-bind="attrs"即可窃爷,使用page-table的地方即可使用所有el-table的屬性和事件邑蒋。

<template>
  <div class="page-table">
    <div class="wrapper">
      <el-table
          ref="elTable"
          v-bind="$attrs"
          v-on="$listeners"
          :data="tableData">
        <slot/>
      </el-table>
      <div style="margin-top: 16px;overflow: hidden">
        <el-pagination
            class="page"
            :current-page="currentPage"
            layout="total, prev, pager, next, jumper"
            :total="total"
            @current-change="handleCurrentChange"/>
      </div>
    </div>
  </div>
</template>

我們有時(shí)候會(huì)碰到有多個(gè)兄弟組件需要傳遞參數(shù)到最外層,如有B組件包含C1和C2,都需要和A交互按厘,定義2個(gè)props使用v-bind即可

<template>
  <div class="page-table">
    <div class="wrapper">
      <el-table
          ref="elTable"
          v-bind="table1Props"
          :data="tableData">
        <slot/>
      </el-table>
      <el-table
          ref="elTable"
          v-bind="table2Props"
          :data="tableData">
        <slot/>
      </el-table>
      <div style="margin-top: 16px;overflow: hidden">
        <el-pagination
            class="page"
            :current-page="currentPage"
            layout="total, prev, pager, next, jumper"
            :total="total"
            @current-change="handleCurrentChange"/>
      </div>
    </div>
  </div>
</template>
<script>
  export default {
    props: {
      table1Props: Object,
      table2Props: Object,
    }
</script>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末医吊,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子逮京,更是在濱河造成了極大的恐慌卿堂,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件懒棉,死亡現(xiàn)場(chǎng)離奇詭異草描,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)策严,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門穗慕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人妻导,你說我怎么就攤上這事逛绵。” “怎么了倔韭?”我有些...
    開封第一講書人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵术浪,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我寿酌,道長(zhǎng)胰苏,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任份名,我火速辦了婚禮碟联,結(jié)果婚禮上妓美,老公的妹妹穿的比我還像新娘僵腺。我一直安慰自己鲤孵,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開白布辰如。 她就那樣靜靜地躺著普监,像睡著了一般。 火紅的嫁衣襯著肌膚如雪琉兜。 梳的紋絲不亂的頭發(fā)上凯正,一...
    開封第一講書人閱讀 49,749評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音豌蟋,去河邊找鬼廊散。 笑死,一個(gè)胖子當(dāng)著我的面吹牛梧疲,可吹牛的內(nèi)容都是我干的允睹。 我是一名探鬼主播,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼幌氮,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼缭受!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起该互,我...
    開封第一講書人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤米者,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后宇智,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蔓搞,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年随橘,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了败明。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡太防,死狀恐怖妻顶,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蜒车,我是刑警寧澤讳嘱,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站酿愧,受9級(jí)特大地震影響沥潭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜嬉挡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一钝鸽、第九天 我趴在偏房一處隱蔽的房頂上張望汇恤。 院中可真熱鬧,春花似錦拔恰、人聲如沸因谎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽财岔。三九已至,卻和暖如春河爹,著一層夾襖步出監(jiān)牢的瞬間匠璧,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工咸这, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留夷恍,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓媳维,卻偏偏與公主長(zhǎng)得像酿雪,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子侨艾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容