Code前端首页关于Code前端联系我们

一、inheritAttrs 是做什么的?

terry 5小时前 阅读数 9 #Vue
文章标签 inheritAttrs;Vue

p>在Vue2写组件时,你有没有遇到过父组件传的属性“悄悄”跑到子组件根元素上?或者想自己决定这些额外属性该绑到哪个元素,却找不到门道?这时候就得聊聊 inheritAttrs 这个配置项啦,下面通过问答形式,把 inheritAttrs 的作用、用法、坑点全讲明白~


Vue2 里每个组件都有个 inheritAttrs 选项,默认值是 true,当父组件给子组件传了属性,但子组件没在 props 里声明,这些“没被声明的属性”(也就是 $attrs 里的内容),默认会被自动加到子组件的 根元素 上,要是把 inheritAttrs 改成 false,这些属性就不会自动往根元素上“贴”了,这时候得自己手动处理这些属性~

举个简单例子:父组件用 <Child name="小明" age="20" />,子组件 props 只声明了 name,这时候 age 没被声明的属性”。inheritAttrstrue(默认),子组件的根元素(<div>)会自动加上 age="20";要是设成 false,根元素就没这个 age 属性了,这时候得用 v-bind="$attrs"age 绑到你想绑的元素上,比如内部的 <span v-bind="$attrs">,这样 age 就跑到 span 上啦。

为啥要控制 inheritAttrs?不能一直用默认的 true 吗?

很多时候组件封装得精细点,默认的 true 可能会搞出麻烦:

场景1:根元素不适合挂额外属性

比如做个自定义按钮组件 <MyButton>,父组件传了个 title 属性(但子组件 props 没声明),默认情况下,这个 title 会跑到按钮的根元素(<button> 标签)上,但如果咱希望 title 只在按钮内部的 tooltip 元素显示,或者根本不想让根元素有多余属性,这时候把 inheritAttrs 设为 false,自己控制属性绑定,就不会“自动乱贴”啦。

场景2:属性该给内部元素用

比如子组件根元素是个 <div>,但父组件传的 placeholdermaxlength 这些属性,明显是给内部 <input> 用的,这时候关闭 inheritAttrs,把这些属性通过 v-bind="$attrs" 绑到 input 上,才符合逻辑——不然根 div 上挂 placeholder,完全没用还影响结构。

简单说,默认 true 适合“属性就是给根元素用”的场景;但组件封装越精细,越需要手动控制 inheritAttrs,避免 DOM 结构里出现多余属性~

inheritAttrs 和 $attrs 啥关系?

这俩经常一起出现,得搞清楚:

  • $attrs 是个对象,存的是 父组件传的、子组件没在 props 声明的所有属性(注意哦,classstyle 是例外,它们不进 $attrs,Vue 会单独处理)。
  • inheritAttrs 是个布尔值,控制的是:这些存在 $attrs 里的属性,要不要自动挂载到子组件的根元素上

举个互动的例子:子组件里 inheritAttrs: false,这时候 $attrs 里的属性不会自动贴到根元素,但 $attrs 本身还在!所以得手动写 v-bind="$attrs",把这些属性绑到你想绑的元素上,比如子组件根是 div,内部有个 input,你想让 input 拿到所有额外属性,就给 inputv-bind="$attrs",这样 input 就能拿到父组件传的 placeholderreadonly 这些属性啦~

实际开发中容易踩的坑有哪些?咋解决?

坑1:根元素莫名多了属性,自己都不知道哪来的

比如父组件传了个 data-test 自定义属性,子组件没声明 props,结果子组件根元素上突然有了 data-test,这就是 inheritAttrs 默认 true 在“搞鬼”。

解决方法:检查子组件的 inheritAttrs,必要时设为 false,再手动把属性绑到该去的地方。

坑2:class 和 style 不受 inheritAttrs 控制

不管 inheritAttrstrue 还是 false,父组件传的 classstyle,都会合并到子组件的根元素上,这是 Vue 专门设计的——因为 classstyle 常用在样式继承。

比如父组件给子组件传 class="red",不管 inheritAttrs 设啥,子组件根元素都会有这个 class,如果不想让根元素有某个 class,得在子组件里手动处理(比如用 computedclass,覆盖掉 unwanted 的类名)。

坑3:多层组件嵌套时,属性透传乱套

比如祖父组件传属性给父组件,父组件再传给子组件,这时候父组件如果没声明 propsinheritAttrs 设为 false,然后在父组件模板里用 <Child v-bind="$attrs" />,才能把属性正确透传到子组件,否则属性可能挂在父组件根元素上,到不了子组件。

有没有具体代码例子,能直观理解?

必须安排!比如封装一个带图标的输入框组件,让父组件传的 placeholdermaxlength 这些属性,精准给到内部的 input 元素:

子组件 IconInput.vue

<template>
  <div class="icon-input">
    <!-- 图标元素 -->
    <i class="icon" :class="iconClass"></i>
    <!-- 输入框,手动绑定 $attrs -->
    <input 
      v-bind="$attrs" 
      :value="value" 
      @input="$emit('input', $event.target.value)"
    />
  </div>
</template>
<script>
export default {
  name: 'IconInput',
  inheritAttrs: false, // 关闭根元素自动挂载额外属性
  props: {
    value: String, // 接收 v-model 的值
    iconClass: String // 接收图标类名
  }
}
</script>
<style scoped>
.icon-input {
  display: flex;
  align-items: center;
}
.icon {
  margin-right: 8px;
}
</style>

父组件使用

<template>
  <div>
    <IconInput 
      v-model="username" 
      iconClass="el-icon-user" 
      placeholder="请输入用户名" 
      maxlength="10"
    />
  </div>
</template>
<script>
import IconInput from './IconInput.vue'
export default {
  components: { IconInput },
  data() {
    return {
      username: ''
    }
  }
}
</script>

解释:父组件传了 placeholdermaxlength,但子组件 props 只声明了 valueiconClass,所以这俩属于“额外属性”,存在 $attrs 里,因为子组件 inheritAttrs: false,根元素 <div class="icon-input"> 不会自动挂载 placeholdermaxlength,而内部的 <input> 通过 v-bind="$attrs",把这两个属性拿到手,这样输入框就能正常显示占位符、限制输入长度,逻辑超合理~

常见疑问快速解答

Q:inheritAttrs 设为 false 后,$attrs 里还有内容吗?

A:有!$attrs 始终存着父组件传的、没被 props 声明的属性(除了 classstyle)。inheritAttrs 只是控制“要不要自动贴到根元素”,不影响 $attrs 本身,所以设为 false 后,得手动用 v-bind="$attrs" 把属性绑到目标元素~

Q:子组件有多个根元素咋办?(Vue2 里允许吗?)

A:Vue2 要求组件必须只有一个根元素,要是写了多个根,编译会直接报错,所以在 Vue2 里,inheritAttrs 控制的永远是 唯一的根元素 是否自动挂载额外属性~

Q:怎么看 $attrs 里具体有啥?

A:可以在子组件的 mounted 钩子打印 this.$attrs

<script>
export default {
  mounted() {
    console.log('当前 $attrs 内容:', this.$attrs)
  }
}
</script>

这样调试的时候,就能清楚看到父组件传了哪些没被声明的属性~

掌握 inheritAttrs,组件封装更灵活

inheritAttrs 是 Vue2 里控制“未声明 props 的父组件属性”挂载行为的关键开关,默认 true 会自动贴到根元素,设为 false 则需要手动通过 $attrs 处理。

在封装基础组件(如 Button、Input)、二次封装第三方组件、写高阶组件时,合理用 inheritAttrs 能避免 DOM 结构冗余,让属性精准绑定到该去的地方,记住它和 $attrs 的配合,以及 class/style 的特殊处理,就能避开大部分坑,写出更专业的组件啦~

(全文围绕 Vue2 inheritAttrs 展开,从概念、作用、关系、坑点、示例到答疑,层层递进讲透用法,实际开发中遇到属性自动挂载、透传混乱等问题,对照这篇内容基本能解决~)

版权声明

本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

热门