$attrs和$listeners,inheritAttrs的使用

1,455 阅读1分钟

前言

今天在开发的时候,发现同事用到了$attrs$listeners,因为此前本人用的很少,所以就去研究了一下,总的来说这两个api就是用来进行组件之间通信的,只不过不用像props和$emit传值t通信那样繁琐,缺点就是不好维护,可读性比较低,因此我们在项目中用的比较少,如果需要跨多个组件通信也会选择Vuex

主要内容

  1. 先来看$attrs$listeners的定义在Vue文档中:
    • vm.$attrs包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。
    • $listeners包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件——在创建更高层次的组件时非常有用。
  2. 再来写个Demo
    • App.vue
    <template>
      <div id="app">
        <Child1 :words1="text1" :words2="text2" :words3="text3" v-on:event1="goEvent1" v-on:event2="goEvent2"></Child1>
      </div>
    </template>
    
    <script>
    import Child1 from "./components/Child1"
    export default {
      name: "App",
      data() {
        return {
          text1: 1,
          text2: 2,
          text3: 3
        }
      },
      methods: {
        goEvent1() {
          console.log("child 提交成功")
        },
        goEvent2(value) {
          console.log(value)
        }
      },
      components: {
        Child1,
      }
    }
    </script>
    
    <style>
    html,
    body {
      height: 100%;
    }
    #app {
      height: 100%;
    }
    </style>
    
    • Child1.vue
    <template>
      <div class="mainWrapper">
        <p>props: {{words1}}</p>
        <p>$attrs: {{$attrs}}</p>
        <button @click="submit()">提交</button>
        <hr>
        <child2 v-bind="$attrs" v-on="$listeners"></child2>
        <!-- 通过$listeners将父作用域中的v-on事件监听器,传入child2,使得child2可以获取到app中的事件 -->
      </div>
    </template>
    
    <script>
    import Child2 from "./Child2"
    export default {
      name: "Child1",
      props: ["words1"],
      data() {
        return {}
      },
      inheritAttrs: true,
      components: { Child2 },
      methods: {
        submit() {
          this.$emit("event1", "child1 提交事件")
        }
      }
    }
    </script>
    
    <style scoped>
    .mainWrapper {
      height: 100px;
    }
    </style>
    
    • Child2.vue
    <template>
      <div>
        <div class="child-2">
          <p>props: {{words2}}</p>
          <p>$attrs: {{$attrs}}</p>
          <input v-model="inputValue" name="" id="" @input="goInput">
        </div>
      </div>
    </template>
    <script>
    export default {
      name: 'Child2',
      props: ['words2'],
      data() {
        return {
          inputValue: ''
        };
      },
      inheritAttrs: false,
      mounted() {
      },
      methods: {
        goInput () {
          this.$emit('event2', this.inputValue);
        }
      }
    }
    </script>
    
  3. 效果
    • 可以看到父组件App.vue中通过v-bind给Child1传递了三个值,在子组件中未被Props接收的值都在$attrs中,其也可以通过v-bind将值传递给Child1的内部组件Child2,同时也可以使用$listeners将父作用域中的v-on事件监听器,传入child2
  4. inheritAttrs 属性以及作用
    • 当一个组件设置了inheritAttrs: false后(默认为true),那么该组件的非props属性(即未被props接收的属性)将不会在组件根节点上生成html属性,以为为对比图

inheritAttrs:false

inheritAttrs:true