美文网首页
Vue - 组件通信之$attrs、$listeners

Vue - 组件通信之$attrs、$listeners

作者: Petricor | 来源:发表于2022-02-25 15:07 被阅读0次

    前言

    vue通信手段有很多种,props/emit、vuexevent bus、provide/inject 等。还有一种通信方式,那就是 $attrs$listeners,这种方式很优雅,使用起来也不赖。下面例子都会通过父(index)、子(child)、孙子(grandson),三者的关系来说明使用方式。

    组件关系图

    $attrs

    官方解释:
    包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。

    我的理解:
    接收除了props声明外的所有绑定属性(class、style除外)

    index.vue
        <child class="arrts"  id="10"   age="20"  sex="男" ></child>
       <!--在 子组件中展示 $arrts:{  "age": "20",  "sex": "男" } ;class和style 特殊的不会被绑定 -->
    
    child.vue
    <template>
      <div class="attrs-one-view">
        <p>$arrts:{{ $attrs }}</p>  <!-- {  "age": "20",  "sex": "男" }  -->
        <div>prop->id: {{ id }}</div> <!-- 10  -->
      </div>
    </template>
    <script>
    export default {
      props: {
        id: {
          type: String,
        },
      },
    };
    </script>
    

    图解:

    父子传值

    解释:
    由于child.vue 在 props 中声明了 id 属性,$attrs 中只有age、gender两个属性,输出结果为:
    { "age": "20", "sex": "男" }
    $attrs 里面接收的是 除了porps里面定义属性之外的值


    • child子组件可以通过 v-bind="$attrs" 定义到grandson.vue 上,把 index.vue 中定义的属性传递到"孙组件"上。让 grandson.vue 也能访问到父组件的属性,这在传递多个属性时会显得很便捷,而不用一条条的进行绑定。

    • 如果想要添加其他属性,可继续绑定属性。但要注意的是,继续绑定的属性和 $attrs 中的属性有重复时,继续绑定的属性优先级会更高

    child.vue -> grandson.vue

    $listeners

    如果$attrs 是操作父子传参的,那$listeners就是操作父组件传递子组件方法的

    官方解释:
    包含了父作用域中不作为 prop 被识别 (且获取) 的 attribute 绑定 (class 和 style 除外)。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定 (class 和 style 除外),并且可以通过 v-bind="$attrs" 传入内部组件——在创建高级别的组件时非常有用。

    我的理解

    • $listeners$attrs 类似,只不过$attrs是v-bind 而 $listeners是用v-on 而已,
    • 接收除了带有.native事件修饰符的所有事件监听器
    index.vue
    <template>
     <child  @getInfo="getInfo"  @getMessage.native="getMessage"></child>
    </template>
    <script>
    export default {
      components: { child, },
      methods: {
        getInfo(val) {
          console.log("getInfo事件来源于index.vue" + val);
        },
        getMessage(val) {
          console.log("getMessage事件来源于index.vue" + val);
        },
      },
    };
    </script>
    
    child.vue
    <template>
      <div class="child-view">
        <grandson v-on="$listeners" @getMessage="getMessage" ></grandson> 
      </div>
    </template>
    <script>
    export default {
      components: { grandson, },
    
      created() {
          console.log(this.$listeners, '====listeners'); 
      },
    };
    //打印结果: 因为在index.vue中getMessage有native修饰,所以不会触发
    // {getInfo: ƒ}getInfo: ƒ invoker()[[Prototype]]: Object '====listeners'
    
    grandson.vue
    <script>
    export default {
      created() {
        console.log(this.$listeners, "====listeners");
      },
    };
    </script>
    
    //打印结果:
    // {getInfo: ƒ, getMessage: ƒ}getInfo: ƒ invoker()getMessage: ƒ invoker()[[Prototype]]: Object '====listeners'
    
    $listeners 事件监听
    • attrs 属性一样,可以通过v-on="$listeners",将事件监听器继续向下传递,让 grandson.vue 访问到事件,且可以使用 $emit 触发 parent.vue 的函数。
    • 如果想要添加其他事件监听器,可继续绑定事件。但要注意的是,继续绑定的事件和 $listeners 中的事件有重复时,不会被覆盖。
      即: 当 grandson.vue 触发 getMessage 事件时,child.vue 和 parent.vue 的事件都会被触发,触发顺序类似于冒泡,先到 child.vue 再到 parent.vue。


      触发冒泡事件

      解释:当index.vue 和child.vue 绑定相同的事件的时候,grandson.vue 会先触发child的事件后触发index.vue 的事件,所以写代码时事件名称不要重复。

    代码地址:码云 vue-question 组件通讯
    参考文档:Vue - 组件通信之attrs、listeners

    相关文章

      网友评论

          本文标题:Vue - 组件通信之$attrs、$listeners

          本文链接:https://www.haomeiwen.com/subject/xfjqrrtx.html