$attrs与$listeners的介绍及使用

879 阅读2分钟

$attrs

1. $attrs的介绍

1.1 正常的父组件向子组件传值:父组件身上通过属性绑定的方式,子组件内部通过props来接收,但是如果组件嵌套过多,那么就需要在每个父组件身上都进行属性绑定,在内部通过props来接收,这样就会导致代码混乱,容易导致错误的发生,这个时候我们就需要使用$attrs

1.2 官方定义:包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (classstyle 除外)。 当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (classstyle 除外),并且可以通过 v-bind="$attrs 传入内部组件.

总结:在父组件身上绑定的属性,在子组件中如果没有通过props的方式获取,那么就会存在子组件的$attrs身上,就可以通过v-bind="$attrs"的方式传入下一个子组件,

2. $attrs的使用

html结构

    <div id="app">
        <one :val="msg" :name="msg1">我是one组件</one>
    </div>

js代码

    // 第一层组件
    Vue.component('one',{
      data(){
        return {
        }
      },
      template:`
        <div>
          <slot></slot>
          <two v-bind="$attrs">我是two组件</two>
        </div>
      `,
      mounted() {
        console.log(this.$attrs);
      },
    })
    
    // 第二层组件
    Vue.component('two',{
      data(){
        return {
        }
      },
      template:`
        <div>
          <slot></slot>
          <tree v-bind="$attrs">我是tree组件</tree>
        </div>
      `,
      mounted() {
        console.log(this.$attrs);
      },
    })
    
    //第三层组件
    Vue.component('tree',{
      data(){
        return {

        }
      },
      template:`
        <div>
          <slot></slot>
          {{this.$attrs}}
        </div>
      `,
      mounted() {
        console.log(this.$attrs);
      },
    })


    new Vue({
      el:"#app",
      data:{
        msg:"多层组件嵌套传值",
        msg1: "app"
      },
    })

代码效果

$listeners

1. $listeners的介绍

1.1 正常的子组件向父组件传值: 通过自定义事件的方式,子组件内部通过$emit的方式触发自定义事件,父组件通过监听自定义事件来接收,但是这样只适用于子组件向父组件传值,如果是孙子辈以及更深层次的组件,那么就需要在每层上都监听自定义事件,并且触发自定义事件,这样就会导致代码不便于阅读,以及容易出错,那么这个时候我们就可以使用$listeners

1.2 官方定义:包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="$listeners" 传入内部组件

总结:子组件触发的事件,都会在父组件的$listeners中,在父组件中就可以通过v-on=$listeners的方式继续向上一层组件传递

2. $attrs的使用

html结构

 <div id="app">
    <one @tree="add($event)">我是one组件</one>
    {{ val }}
 </div>

js代码

    Vue.component('one', {
      data() {
        return {

        }
      },
      props: ['val'],
      template: `
        <div>
          <slot></slot>
          <two v-on="$listeners">我是two组件</two>
        </div>
      `,
      mounted() {
        console.log(this.$listeners);
      },
    })
    
    
    Vue.component('two', {
      data() {
        return {

        }
      },
      template: `
        <div>
          <slot></slot>
          <tree v-on="$listeners">我是tree组件</tree>
        </div>
      `,
      mounted() {
        console.log(this.$listeners);

      },
    })
    
    
    Vue.component('tree', {
      data() {
        return {}
      },
      template: `
        <div>
          <slot></slot>
          <button @click="add('我是tree组件想根组件传递的值')">点击我想根组件传值</button>
        </div>
      `,
      mounted() {},
      methods: {
        add(p) {
          this.$emit('tree', p)
        }
      }
    })


    new Vue({
      el: "#app",
      data: {
        val: "123",
      },
      methods: {
        add(val) {
          this.val = val;
        }
      },
    })

初始效果

按钮点击后效果