Vue使用$attrs与$listeners实现多层嵌套传递

官方文档中的解释 cn.vuejs.org/v2/guide/co…html

现有3个嵌套组件,A->B,B->C。 如今我么须要在A中对C的props赋值,监听C的emit事件 vue

图片

A组件与C组件通讯,咱们有多少种解决方案?vuex

  1. 咱们使用vuex来进行数据管理,依赖于vuex咱们能够一次改变,任何一个组件中都能获取。可是若是多个组件共享状态比较少,使用vuex过于麻烦和难以维护。element-ui中大量采用此方法。
  2. 自定义vue bus事件总线,原理相似vuex,使用特别简单。bus适合碰到组件跨级兄弟组件等无明显依赖关系的消息传递,原生app开发中常常用到,可是缺点是bus破坏了代码的链式调用,大量的滥用将致使逻辑的分散,出现问题后很难定位,下降了代码可读性。
  3. 使用B来作中转,A传递给B,B再给C**,**这是最容易想到的方案,可是若是嵌套的组件过多,须要传递的事件和属性较多,会致使代码繁琐,代码维护困难。

对于咱们这种状况,3种方式都有局限性element-ui

在vue2.4中,为了解决该需求,引入了$attrs$listeners,新增了inheritAttrs选项。咱们只须要在B组件中对引入的C组件增长下面两个属性便可绑定全部的属性和事件。bash

<C v-bind="$attrs" v-on="$listeners"></C>
复制代码

A组件app

<template>
<div>
  <h2>组件A 数据项:{{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组件ide

<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组件ui

<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>
复制代码

实际应用

element-ui开发的后台项目中,大量使用到了el-tableel-pagination作分页数据展现,因此我封装一个自定义组件page-tablethis

<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属性和事件。咱们在page-table中把全部el-table的属性和事件都中转一遍?有上百个呢。spa

只需在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>

复制代码

咱们有时候会碰到有多个兄弟组件须要传递参数到最外层,若有B组件包含C1和C2,都须要和A交互,定义2个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>
复制代码
相关文章
相关标签/搜索