【Vue】组件通信之$attrs、$listeners 以及inheritAttrs补充

821 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

对上一篇文章:juejin.cn/post/701211… 子组件点击事件 在父组件接收的进行补充!

  • 孙组件怎样发送事件给父组件监听到呢? image.png

$attrs

  • attrs是在vue2.40版本以上添加的。项目中有多层组件传参可以使用attrs是在vue的2.40版本以上添加的。项目中有多层组件传参可以使用attrs, 可以使代码更加美观,更加简洁,维护代码的时候更方便。如果使用普通的父子组件传参prop和emitemit, on会很繁琐;如果使用vuex会大材小用,只是在这几个组件中使用,没必要使用vuex;使用事件总线eventBus,使用不恰当的话,有可能会出现事件多次执行。 如果给组件传递的数据,组件不使用props接收,那么这些数据将作为组件的HTML元素的特性,这些特性绑定在组件的HTML根元素上

inheritAttrs

  • inheritAttrs: false的含义是不希望本组件的根元素继承父组件的attribute,同时父组件传过来的属性(没有被子组件的props接收的属性),也不会显示在子组件的dom元素上,但是在组件里可以通过其$attrs可以获取到没有使用的注册属性, inheritAttrs: false是不会影响 style 和 class 的绑定

在很多开发情况下,我们只是想把A组件的信息传递给C组件,如果使用props 绑定来进行信息的传递,虽然能够实现,但是代码并不美观。

  • 父组件:
<template>
  <div>
    <childDom :foo="foo" :zoo="zoo"> </childDom>
  </div>
</template>

<script>
import childDom from '../../components/childDom';
export default {
  name: "userProfileindex",
  components:{childDom},
  data() {
    return {
      foo: "Hello, foo",
      zoo: "Hello, zoo"
    };
  }
};
</script>

  • 子组件:
<template>
   <div>
      <p>foo:{{foo}}</p>
   </div>
</template>
<script>
export default {
 name:'childDom',
 props:["foo"]
}
</script>

  • 当显示父组件时,查看Dom结构,结构如下

image.png 给子组件关联数据,子组件如果不用props接收,那么这些数据就作为普通的HTML特性应用在子组件的根元素上

  • 在2.4中新增选项inheritAttrs inheritAttrs的默认值为true, 将inheritAttrs的值设为false, 这些默认的行为会禁止掉。但是通过实例属性 $attrs ,可以将这些特性生效,且可以通过v-bind 绑定到子组件的非根元素上。

  • 修改子组件代码如下:


<template>
   <div class="child">
       <span>子组件:</span>
      <p>foo:{{foo}}</p>
      <p>attrs:{{$attrs}}</p>
      <childDomChild v-bind="$attrs"></childDomChild>
   </div>
</template>
<script>
import childDomChild from '../childDomChild/index.vue';

export default {
 name:'child-dom',
 components: {
   childDomChild  
 },
 props:["foo"],
 inheritAttrs:false,
}
</script>
<style  scoped>
    .child{
        color: rgb(223, 177, 26);
        border: 4px solid slateblue;
          margin: 16px;
    }
</style>

  • 新增子组件 childDomChild
<template>
  <div class="son">
    <span>孙组件:</span>
   <p>zoo:{{zoo}}</p>
  </div>
</template>
<script>
  export default {
    name:'childDomChild',
    props:["zoo"],
    inheritAttrs:false
  }
</script>
<style  scoped>
    .son{
         margin: 16px;

        color: tomato;
        border:3px solid violet;
    }
</style>

  • 输出的结果如下: image.png 从上面的代码,可以看出使用$attrs ,inheritAttrs 属性 能够使用简洁的代码,将A组件的数据传递给C组件 , 该场景的使用范围还是挺广的。

此时我们又想到了一个问题,c组件的信息,怎么同步给a组件呢? 用到了“$listeners”

vue2.4版本新增了listeners属性,我们在子(B)组件上绑定von=listeners 属性,我们在子(B)组件上 绑定 v-on=”listeners”, 在父(A)组件中,监听孙组件触发的事件。就能把孙(C)组件发出的数据,传递给父(A)组件。

image.png 父组件代码更新如下:

<template>
  <div class="father">
    <span>父组件:</span>
    <childDom :foo="foo" :zoo="zoo"  v-on:upRocket="reciveRocket"> </childDom>
  </div>
</template>

<script>
import childDom from '../../components/childDom';
export default {
  name: "userProfileindex",
  components:{childDom},
  data() {
    return {
      foo: "Hello, foo",
      zoo: "Hello, zoo"
    };
  },
   methods:{
   reciveRocket(res){
      console.log("接收到来自孙组件的click事件",res)
   }
 }
};
</script>
<style  scoped>
  .father{
    color: rgb(31, 32, 32);
    border: 2px solid springgreen;
  }
</style>

  • 子组件更新如下: 孙组件加上v-on="$listeners

<template>
   <div class="child">
       <span>子组件:</span>
      <p>foo:{{foo}}</p>
      <p>attrs:{{$attrs}}</p>
      <childDomChild v-bind="$attrs"  v-on="$listeners"></childDomChild>
   </div>
</template>
<script>
import childDomChild from '../childDomChild/index.vue';

export default {
 name:'child-dom',
 components: {
   childDomChild  
 },
 props:["foo"],
 inheritAttrs:false,
}
</script>
<style  scoped>
    .child{
        color: rgb(32, 28, 13);
        border: 4px solid slateblue;
          margin: 16px;
    }
</style>

  • 孙组件更新:
<template>
  <div class="son">
    <span>孙组件:</span>
    <p>zoo:{{ zoo }}</p>
    <button @click="startUpRocket">我要发射火箭</button>
  </div>
</template>
<script>
export default {
  name: "childDomChild",
  props: ["zoo"],
  inheritAttrs: false,
  methods: {
    startUpRocket() {
      this.$emit("upRocket",'孙组件参数:哈哈哈');
      console.log("孙组件要发射火箭-->startUpRocket");
    }
  }
};
</script>
<style scoped>
.son {
  margin: 16px;

  color: tomato;
  border: 3px solid violet;
}
</style>