Vue 中的 inheritAttrs 和 $attrs
inheritAttrs 是组件的一个属性,有 true 和 false 两个值。默认情况下 vue 会把父作用域的不被认作 props 的特性绑定且作为普通的 HTML 特性应用在子组件的根元素上,例如:
<div id="app">
<children-component :name="name" :age="age"></children-component>
</div>
var vm = new Vue({
el: "#app",
data: {
name: "juliet",
age: 23
},
components: {
"chilren-component": {
props: ["name"],
template: `<div>{{ name }}</div>`
}
}
})
而最终渲染出来是下面这样:
<div id="app">
<div age="23">juliet</div>
</div>
age 被当作子组件根元素上的属性了,而在某些特定场景下为我们不希望出现这种情况,那么可以在子组件中加上 inheritAtrrs = false 属性,如下所示:
var vm = new Vue({
el: "#app",
data: {
name: "juliet",
age: 23
},
components: {
"chilren-component": {
props: ["name"],
inheritAttrs: false,
template: `<div>{{ name }}</div>`
}
}
})
这样最终渲染出来是下面这样的:
<div id="app">
<div>juliet</div>
</div>
age 不再被渲染为子组件根元素上的属性了,那要怎么获得 age 的值呢,这时就可以用 $attrs 来获取了:
var vm = new Vue({
el: "#app",
data: {
name: "juliet",
age: 23
},
components: {
"chilren-component": {
props: ["name"],
inheritAttrs: false,
template: `
<div>
<div>{{ name }}</div>
<div>{{ $attrs.age }}</div>
</div>
`
}
}
})
最终渲染出来的是下面这样的:
<div id="app">
<div>
<div>juliet</div>
<div>23</div>
</div>
</div>
所以 $attrs 是包含了在父组件中除了注册在 props 中的其余属性的对象。它还有另外一个作用,假设现在有父子孙三个组件,如果想让父组件传值给孙组件该怎么办,常规办法就是利用 props 一级一级的往下传递,如下所示:
<div id="app">
<children-component :name="name" :age="age"></children-component>
</div>
var vm = new Vue({
el: "#app",
data: {
name: "juliet",
age: 23
},
components: {
"children-component": {
props: ["name", "age"],
template: `
<div>
<div>{{ name }}</div>
<grand-component :age="age"></grand-component>
</div>
`,
components: {
"grand-component": {
props: ["age"],
template: `
<div>{{ age }}</div>
`
}
}
}
}
})
最终渲染出来的效果如下:
<div id="app">
<div>
<div>juliet</div>
<div>23</div>
</div>
</div>
虽然达到了最终的效果,但是子组件并没有使用到 age 的值,但由于孙组件要使用 age,所以它不得不接收父组件传过来的 age 并且将其传给孙组件。现在只有 3 层组件,如果有 5 层甚至十几层呢,得写很多多余的 props 和 attribute 来传递值。但是使用 $attrs 就不用这么麻烦,如下所示,HTML 代码和上面相同,javascript代码不同:
var vm = new Vue({
el: "#app",
data: {
name: "juliet",
age: 23
},
components: {
"children-component": {
props: ["name"],
template: `
<div>
<div>{{ name }}</div>
<grand-component v-bind="$attrs"></grand-component>
</div>
`,
inheritAttrs: false,
components: {
"grand-component": {
template: `
<div>{{ $attrs.age }}</div>
`,
inheritAttrs: false
}
}
}
}
})
渲染出来的和上面的结果一模一样,但是因为 age 属性是传给孙组件的,子组件的 props 中就不需要传 age 属性了,而是直接通过 v-bind="$attrs" 传给孙组件即可。
这里需要注意的是,inheritAttrs: false 不会影响 style 和 class 的绑定,也就是说在父组件对子组件的 style 和 class 属性进行了设置,那么即使子组件设置了 inheritAttrs: false,这两个属性还是会合并到子组件的根元素上。