一、inheritAttrs 是做什么的?
p>在Vue2写组件时,你有没有遇到过父组件传的属性“悄悄”跑到子组件根元素上?或者想自己决定这些额外属性该绑到哪个元素,却找不到门道?这时候就得聊聊 inheritAttrs
这个配置项啦,下面通过问答形式,把 inheritAttrs
的作用、用法、坑点全讲明白~
Vue2 里每个组件都有个
inheritAttrs
选项,默认值是 true
,当父组件给子组件传了属性,但子组件没在 props
里声明,这些“没被声明的属性”(也就是 $attrs
里的内容),默认会被自动加到子组件的 根元素 上,要是把 inheritAttrs
改成 false
,这些属性就不会自动往根元素上“贴”了,这时候得自己手动处理这些属性~
举个简单例子:父组件用 <Child name="小明" age="20" />
,子组件 props
只声明了 name
,这时候 age
没被声明的属性”。inheritAttrs
是 true
(默认),子组件的根元素(<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>
,但父组件传的 placeholder
、maxlength
这些属性,明显是给内部 <input>
用的,这时候关闭 inheritAttrs
,把这些属性通过 v-bind="$attrs"
绑到 input
上,才符合逻辑——不然根 div
上挂 placeholder
,完全没用还影响结构。
简单说,默认 true
适合“属性就是给根元素用”的场景;但组件封装越精细,越需要手动控制 inheritAttrs
,避免 DOM 结构里出现多余属性~
inheritAttrs 和 $attrs 啥关系?
这俩经常一起出现,得搞清楚:
$attrs
是个对象,存的是 父组件传的、子组件没在props
声明的所有属性(注意哦,class
和style
是例外,它们不进$attrs
,Vue 会单独处理)。inheritAttrs
是个布尔值,控制的是:这些存在$attrs
里的属性,要不要自动挂载到子组件的根元素上。
举个互动的例子:子组件里 inheritAttrs: false
,这时候 $attrs
里的属性不会自动贴到根元素,但 $attrs
本身还在!所以得手动写 v-bind="$attrs"
,把这些属性绑到你想绑的元素上,比如子组件根是 div
,内部有个 input
,你想让 input
拿到所有额外属性,就给 input
加 v-bind="$attrs"
,这样 input
就能拿到父组件传的 placeholder
、readonly
这些属性啦~
实际开发中容易踩的坑有哪些?咋解决?
坑1:根元素莫名多了属性,自己都不知道哪来的
比如父组件传了个 data-test
自定义属性,子组件没声明 props
,结果子组件根元素上突然有了 data-test
,这就是 inheritAttrs
默认 true
在“搞鬼”。
解决方法:检查子组件的 inheritAttrs
,必要时设为 false
,再手动把属性绑到该去的地方。
坑2:class 和 style 不受 inheritAttrs 控制
不管 inheritAttrs
是 true
还是 false
,父组件传的 class
和 style
,都会合并到子组件的根元素上,这是 Vue 专门设计的——因为 class
和 style
常用在样式继承。
比如父组件给子组件传 class="red"
,不管 inheritAttrs
设啥,子组件根元素都会有这个 class
,如果不想让根元素有某个 class
,得在子组件里手动处理(比如用 computed
拼 class
,覆盖掉 unwanted 的类名)。
坑3:多层组件嵌套时,属性透传乱套
比如祖父组件传属性给父组件,父组件再传给子组件,这时候父组件如果没声明 props
,inheritAttrs
设为 false
,然后在父组件模板里用 <Child v-bind="$attrs" />
,才能把属性正确透传到子组件,否则属性可能挂在父组件根元素上,到不了子组件。
有没有具体代码例子,能直观理解?
必须安排!比如封装一个带图标的输入框组件,让父组件传的 placeholder
、maxlength
这些属性,精准给到内部的 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>
解释:父组件传了 placeholder
和 maxlength
,但子组件 props
只声明了 value
和 iconClass
,所以这俩属于“额外属性”,存在 $attrs
里,因为子组件 inheritAttrs: false
,根元素 <div class="icon-input">
不会自动挂载 placeholder
和 maxlength
,而内部的 <input>
通过 v-bind="$attrs"
,把这两个属性拿到手,这样输入框就能正常显示占位符、限制输入长度,逻辑超合理~
常见疑问快速解答
Q:inheritAttrs 设为 false 后,$attrs 里还有内容吗?
A:有!$attrs
始终存着父组件传的、没被 props
声明的属性(除了 class
和 style
)。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前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。