组件通信-$attrs和$listeners

1,196 阅读2分钟

vue中的$attrs是什么?

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

通俗的说就是,attrs可以将父作用域中绑定的属性传递给子组件,直接用attrs可以将父作用域中绑定的属性传递给子组件,直接用attrs就能在子组件接收到父组件所绑定的属性,还可以将父组件绑定的属性(class 和 style 除外,id也会传递)传递给孙子组件,只需要在子组件上通过用v-bind="$attrs"绑定,就能把在子组件中没有用props注册的属性(class 和 style 除外,id也会传递)传递给孙子组件,只说不练不能算是学习,所以我们来看代码

vue中的$listeners是什么?

包含了父作用域中的 (不含 .native 修饰器的) v-on 事件监听器。它可以通过 v-on="listeners"传入内部组件——在创建更高层次的组件时非常有用(我不理解什么是更高级组件20211228)。简单点讲它是一个对象,里面包含了作用在这个组件上所有的监听器(监听事件),可以通过von="listeners" 传入内部组件——在创建更高层次的组件时非常有用(我不理解什么是更高级组件-2021-12-28)。 简单点讲它是一个对象,里面包含了作用在这个组件上所有的监听器(监听事件),可以通过 v-on="listeners" 将事件监听指向这个组件内的子元素(包括内部的子组件)。

我将它理解为在祖父组件上绑定了一个事件在父组件要触发这个组件就是emit,这很常规,要是想在孙子组件上去触发它,直接写emit,这很常规,要是想在孙子组件上去触发它,直接写emit是不行的,需要在父组件上写上v-on="listeners",这样在孙子组件中就能用listeners",这样在孙子组件中就能用emit去触发祖父元组中的写的事件

inheritAttrs

默认值:ture (显示)

默认情况下父作用域的不被认作 props 的特性绑定 (attribute bindings) 将会“回退”且作为普通的 HTML 特性应用在子组件的根元素上。

我的理解就是在html结构的标签上先不显示出来。例如我在父组件上写了 inheritAttrs: true (其实是默认值写不写都一样,孙子组件和父组件根元素html结构上都显示传递的$attrs的值)浏览器的html结构上显示如下

在父组件上写 inheritAttrs: false,则父组件的根元素上不会显示,孙子组件还会显示,这样对比明显,如下图

示例代码

祖父组件代码:

///祖父组件
<template>
    <father
      class="father"
      id="testid"
      @say="speech"
      :data="list"
      :time="date"
      prop="$attrs不会传递child组件中定义的props值,因为在father中用props注册了"
    ></father>
</template>
<script>
import father from "./father.vue";
export default {
  components: {
    father,
  },
  data() {
    return {
      list: [{ name: "小🐎" }, { name: "小🐖" }],
      date: "2021-12-28",
      week: "星期二",
    };
  },
  methods: {
    speech(params) {
      console.log("i am grandfather", params);
    },
  },
};
</script>
<style lang="less" scoped>
.father {
  color: red;
}
</style>

此时给父组件绑定的有data,time,id,prop,class

父组件代码:

////父组件代码
<template>
  <p>
    父组件:{{ this.$attrs["data"] }}
    <children v-bind="$attrs" v-on="$listeners"></children>
  </p>
</template>

<script>
import children from "./children.vue";
export default {
  inheritAttrs: true,
  props: ["prop"],
  components: {
    children,
  },
  data() {
    return {};
  },
  created() {
    this.$emit("say", "father触发的传的参数");>>>>i am grandfather father触发的传的参数
  },
};
</script>

此时父组件通过用props将prop注册使用了,所以在attrs中将prop剔除,并且attrs中将prop剔除,并且attrs不会传递class和style所以将class剔除,$attrs能传递给孙子组件的就还剩下data,time,id

孙子组件代码:

///孙子组件代码
<template>
    <div>子组件:{{ this.$attrs }}</div>
    <!-- <div>子组件:{{ data }}--{{time}}</div> -->
</template>

<script>
export default {
  // props: {data:{
  //   type: Array,
  //   dedault: () => []
  // },time:{
  //   type:String,
  //   default:""
  // }},
  props:['data'],
  data() {
    return {};
  },
  created() {
    this.$emit('say','children触发的传的参数')>>>>>i am grandfather children触发的传的参数
    console.log(this.$attrs);>>>>>{id: 'testid', data: Array(2)}
  },
};
</script>

这里虽然接收到data,time,id,但是用props注册了time所以此时$attrs只剩下了data,id

浏览器输出结果

html显示:

inheritAttrs: true

inheritAttrs: false