$attrs$listeners的主要应用是实现多层嵌套传递。
在这里插入图片描述
组件A与组件B通信一般都会使用组件B中转,即A传递给B,B再给C,但是如果A到C组件之间嵌套的组件过多,需要传递的事件和属性较多,会导致代码繁琐,代码维护困难。在vue2.4中,为了解决该需求,引入了$attrs$listeners,新增了inheritAttrs选项。

$attrs的使用

官方定义:
包含了父作用域中不作为prop 被识别 (且获取) 的特性绑定 (classstyle除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (classstyle除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。
(好抽象一脸懵逼。。。)
$attrs只代表的是那些没有被声明为props的属性,如果某个prop被子组件中声明了(就是这个属性已经在子组件的props中了),在子组件中的$attr会把声明的prop剔除。
个人理解: 一个组件在父组件中被引用,$attrs就是组件标签上的静态属性值(attr)和动态属性值(:attr)的对象集合,这个集合不包含classstyle和事件属性

// 父组件
<child-com class="com" name="attr" :foo="foo" :boo="boo" :coo="coo" :doo="doo" @click="test"></child-com>
...
data() {
  return {
    foo: 'Hello World!',
    boo: 'Hello Javascript!',
    coo: 'Hello Vue',
    doo: 'Last'
  }
},
...

// child-com.vue
 export default {
  name: 'childCom',
  components: {
    childCom2
  },
  created() {
    console.log(this.$attrs) // {name: "attr", foo: "Hello World!", boo: "Hello Javascript!", coo: "Hello Vue", doo: "Last"}
  }
}

如果子组件声明了$prop$attrs中与$props相同的属性会被移除

// child-com.vue
 export default {
  name: 'childCom',
  props: ['foo'], // foo被声明
  components: {
    childCom2
  },
  created() {
    console.log(this.$attrs) // {name: "attr", boo: "Hello Javascript!", coo: "Hello Vue", doo: "Last"}
  }
}

如果childCom里的子组件还用到foo,可以继续将foo传给子组件

<template>
  <div>
    <p>foo: {{foo}} </p>
    <child-com2 :foo="foo" v-bind="$attrs"></child-com2>
  </div>
</template>

<script>
const childCom2 = () => import('./childCom2.vue')
export default {
  name: 'childCom1',
  props: ['foo'], // foo作为props属性绑定
  inheritAttrs: false,
  components: {
    childCom2
  },
  created() {
    console.log(this.$attrs) // {name: "attr", boo: "Hello Javascript!", coo: "Hello Vue", doo: "Last"}
  }
}
</script>

//childCom2.vue
created() {
    console.log(this.$attrs) // {foo: "Hello World!", name: "attr", boo: "Hello Javascript!", coo: "Hello Vue", doo: "Last"}
  }

inheritAttrs要设置成false还是true(默认)看下图就知道
在这里插入图片描述
在这里插入图片描述
$props比较
$props必须在组件中注册了props才能用拿到值,所以在嵌套层级比较深的组件中$attrs拿值更加便捷

$listeners的使用

包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过v-on=”$listeners”传入内部组件。
归纳起来也是两点:

  • $listeners是组件的内置属性,它的值是父组件(不含.native修饰器的) v-on事件监听器。
  • 组件可以通 过在自己的子组件上使用v-on=”$listeners”,进一步把值传给自己的子组件。如果子组件已经绑定$listener中同名的监听器,则两个监听器函数会以冒泡的方式先后执行。
    父组件:
 <template>
    <div class="test">
        <child  v-bind="{name, sex, age}" v-on="{changeName,changeAge}"></child>
    </div>
</template>

<script>
import child from './child'

export default {
    data() {
        return {
          name: '张三',
          sex: '男',
          age: 11,
        }
    },
    components: {
        child
    },
    methods: {
        changeName(name) {
            this.name = name
        },
        changeAge(age) {
            this.age = age
        }
    }
}
</script>

子组件child.vue

<template>
    <div class="child">
        child组件的$attrs {{$attrs}}
        <child-child v-bind="$attrs" v-on="$listeners" @showAttrs="showAttrs"></child-child>
    </div>
</template>

<script>
import childChild from  './child-child'
export default {
    name: "child",
    props: ['name'],
    inheritAttrs: false,
    created() {
        console.log('child', this.$listeners) 
    },
    components: {
        childChild
    },
    methods: {
        showAttrs() {
            console.log(this.$attrs)
        }
    }
}
</script>

孙子组件:child-child.vue

<template>
    <div class="child-child">
        child-child组件的$attrs {{$attrs}}
    </div>
</template>

<script>
export default {
    name: "child-child",
    inheritAttrs: false,
    created() {
      console.log('child-child',this.$listeners)  
    }
}
</script>

打印结果:
在这里插入图片描述

Logo

前往低代码交流专区

更多推荐