vue3 `inheritAttrs`属性继承与`$attrs`使用与讲解

44 篇文章 6 订阅
29 篇文章 0 订阅

说明:vue3小版本更新、补丁等带来的改动会导致可能文章讲解的内容与实际使用不一致。(已经碰上了。。),版本功能已稳定下来了,也不用怕。

版本:vue:3.2.31 ;

版本时间:2022-3-17 的最新版;

文章更新时间:2022-4-4


  • $attrs

    • 类型:Object

    • 仅可读

先讲解 $attrs ,这样与`inheritAttrs`结合起来更容易理解。

  1. 重点:包含了父作用域中不作为组件 `props` 或 `emit`自定义事件的 attribute 绑定和事件。
    官方这句话后半段其实不太对,$attrs包含了所有 绑定在子组件上的v-on事件!跟JS原生一样的事件名则会继承到对应绑定的元素上。
  2. 当一个组件没有声明任何 props 时,这里会包含所有父作用域的绑定,并且可以通过 v-bind="$attrs" 传入内部组件——这在创建高阶的组件时会非常有用。
  3. 讲解涉及 v-bind 知识,若不了解,请先去看 v-bind ;
  4. ` $attrs `不包含内容补充:vue内置的2个特殊attribute,vue的所有内置指令、包括自定义指令;
    1. (但 v-on、v-bind 这2个包含,例如v-on:click会被解析成 onClick,而v-bind只是表示可动态绑定这个属性的值 。)
    2. 既然讲到了自定义指令,说一嘴:自定义指令绑定子组件时,若子组件是单根节点组件,则指令根节点会作用于根节点!与 inheritAttrs 继承和 $attrs 都无关!!

 $attrs 对象不包含的有:

1、vue内置的特殊attribute:key  ref。
2、vue的所有内置指令(v-on、v-bind 除外)
3、所有自定义的 directive 指令
4、当前组件的 props 内声明的所有 prop 名称
5、当前组件的 emits 内声明的所有自定义的事件名

$attrs 对象包含的内容有:

上面写的都不包含,那没写的当然都包含啦。。不然上面的我辛辛苦苦记录 列出来干啥。。


案例1: 

// 父组件里 使用 nested 子组件
    <nested 
      style="color: rgb(0, 217, 255);" 
      class='a' id="b" 
      data-set='data测试' 
      @click.once='attrsFn' @input='attrsFn' @blur='attrsFn' 
      @customEmitsFn='customFn' 
      :dynAttrs='{dy:666}'
      :fnAttr='attrsFn'
      :is='isdA'
      :testAttr='"这个是props,上面的全是测试$attrs包含的内容"'
    >
    </nested> 
// 代码里 nested 子组件打印如下内容
<template>
  <div>无关内容</div>
  <div :='$attrs'>$attrs测试后</div>
</template>
<script>
export default defineComponent({
  inheritAttrs:false,
  props:['testAttr'],
  mounted(){
    console.log(this.$attrs,'nested组件的attr');
    console.log(this.$props,'nested组件的props');
  }
}
</script>


// 子组件在浏览器上的 html 结果
<div class="a" id="b" 
  data-set="data测试" 
  dynattrs="[object Object]" 
  fnattr="function () { [native code] }" 
  is="[object Object]" 
  style="color: rgb(0, 217, 255);"
>$attrs测试后</div>

 该图为子组件的 $attrs 打印内容

案例2:

这种绑定方式会将$attrs对象上的所有键值对都绑定为该标签的上。

`.prop`、`.attr` 这2个特例,prop是元素的property,attr则是元素的attribute。(使用这2个修饰符的,在$attrs对象上的key值带有特殊前缀)

inheritAttrs 是true还是false,都与 $attrs 的使用无任何关系和影响。

但是 v-bind="$attrs" 是否有使用会影响 inheritAttrs 的警告是否提示!(下面 `inheritAttrs案例2`中有说明)

// 这是子组件
<template>
  <div calss='demosss'>
    <div class='child' ref="childRef" v-bind='$attrs'>
      <span v-bind='$attrs'>属性绑定测试</span>
    </div>
  </div>
  <div>....</div>

  <!-- 可再传给下个子组件 -->
  <nested v-bind='$attrs'></nested>
</template>
<script setup>
import { useAttrs } from 'vue'
const attrs = useAttrs()
console.log(attrs);  // {} :包含所有attr的键值对
</script>

原理:在 v-bind 指令中有如下写法,所以上述的 v-bind='$attrs' 等于将 非prop 的属性 绑定到指定的标签。

<!-- 绑定一个全是 attribute 的对象 -->
<div v-bind="{ id: someProp, 'other-attr': otherProp }"></div>

 其他相关案例:

  • .prop - 将一个绑定强制设置为一个 DOM property,参数是引用的形式。3.2+
  • .attr - 将一个绑定强制设置为一个 DOM attribute,参数固定是字符串。3.2+
  • 以上2个都能通过组件实例属性 $attrs 获取。
<template>
  <div :testShowWhat.prop="110">强制为prop,所以不会被当成 attribute </div>
  1.<nested :testAttr.attr="'强制为attribute'" :testAttr='"这个就是props"' >tip:报错但有效,报错原因 vloar版本?</nested> 

  2.<!-- .testAttr 是 :testAttr.prop 的缩写; -->
    <!-- ^testAttr 是 :testAttr.attr 的缩写,这个文档实际没写; -->
  <nested :testAttr.prop="110"></nested>

  3.<nested v-bind='$attrs'></nested>
</template>

注意, `.prop`设置的并非是组件通信的props,是元素的 `property` ,所以给组件设置为`.attr`与`.prop`,组件设置了对应的props的属性名都无法接收到;


`.attr` 和 `.prop` 和 ` :testAttr="" `能一起使用。毕竟3个作用都不一样,不会互相影响,一个设置为标签attribute,一个是设置为标签元素的property,一个是作为组件通信的props。

property获取方式:this.$refs.refElName.propertyName


  • inheritAttrs

    • 类型:Boolean

    • 默认:true

不会被继承的有:

vue内置的特殊attribute是不会继承的。
emits 选项中列出的事件不会被组件的根元素继承;
props 内声明的 prop 属性名也不会被当做 普通 attr 被继承。


请注意:指令不属于继承的范畴!
(v-on、v-bind 除外,v-on:click会被解析成 onClick,而v-bind只是表示可动态绑定这个属性的值 );
当v-xxx指令绑定到子组件时,该子组件如果是单根节点,则会添加到该根节点中,片段组件则指令直接无效,与 inheritAttrs 是true还是false都无关!!

会被继承的有: 

1、当组件返回单个根节点时,非 prop 的 attribute 将自动添加到根节点的 attribute 中。
2、当组件返回单个根节点时,非 emit 声明的事件 将自动添加到根节点的 `原生DOM事件` 中。

案例1:inheritAttrs: true

// 父组件引用
<customEvent
  @click="testEvent" testAttr='testAttr_value' testAttr2='testAttr2' class="bushiba?"
  @myEvent="emitFN" ref="childtest"
>
</customEvent>

// 子组件 customEvent
<template>
  <div> 
    根节点这个 div 标签将继承非props的所有 attr 和 事件;
    (vue内置的特殊attribute是不会继承的)

    <div>单节点组件1</div>
    <div>单节点组件2</div>
  </div>
</template>
<script>
import { defineComponent } from 'vue'
export default defineComponent({
  inheritAttrs: true,
})
</script>

当template有根元素的时候,绑定到组件上的属性和事件会自动继承到根元素上

案例2:inheritAttrs: true ; 并且组件为多节点!

如果组件是片段(多节点),并且使用该组件时,组件标签绑定了attr和事件,这些都不会继承,并且会抛出警告!

也就是说,片段组件需要将 inheritAttrs 设置为 false。当然不设置为 false 也有个好处,抛出警告告诉编程人员,这个组件是多节点的!你对该组件标签设置的 attr 和 事件等全都无效!

// 父组件引用
<customEvent
  @click="abc" testAttr='testAttr_value' testAttr2='testAttr2' class="bushiba?"
  @myEvent="emitFN" ref="childtest"
>
</customEvent>

// 子组件 customEvent
<template>
  <div>无根节点组件:片段</div>
  <div>无根节点组件:片段</div>
</template>
<script>
import { defineComponent } from 'vue'
export default defineComponent({
  inheritAttrs: true,
})
</script>

其中一个重点回顾来了! 

还记得上面的 $attr 吗,组件为多根节点,且 inheritAttrs: true 的时候,

如果该组件使用有` v-bind="$attrs" `,组件标签绑定了attr和事件,是不会抛出警告的!但是也不会继承这些 attr 和 事件。

案例3:inheritAttrs: false

懒得写案例了,直接说就都懂了。

设置为false后,不论单节点还是多节点的组件,都不会继承任何 attr 和 事件!


注意 `案例2` 所说的:【如果组件是片段(多节点),并且组件标签绑定了attr和事件,都不会继承,并且会抛出警告!】,但是在`inheritAttrs: false`的情况下,不会抛出警告!

禁止继承的内容有:attribute、各种事件(emit事件除外)


记忆小结:

  1. inheritAttrs是继承,所以只需要关心被继承的组件(子组件)是否是单个根节点还是多个根节点(片段)就行了。
  2. ` v-bind="$attrs" ` 是将 `$attrs`对象里的内容绑定到该标签(元素),跟继承没任何关系!

虽然使用v-bind="$attrs" 后,inheritAttrs错误使用时不会抛出警告。但以上2个不要混为一谈,功能作用点不一样,也互不影响对方。

最后的最后:

这些内容,有很多细节,纠正过文章内容,现在应该没错的了,但万一嘛,又或者我理解还不够深,所以欢迎大家留言补充、交流、探讨!!!


QQ交流群:522976012  ,欢迎来玩。

聚焦vue3,但不限于vue,任何前端问题,究其本质,值得讨论,研究与学习。

  • 8
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值