$attrs
属性解释:包含了父作用域中不作为组件 props 或自定义事件的 attribute 绑定和事件。当一个组件没有声明任何 prop 时,这里会包含所有父作用域的绑定,并且可以通过 v-bind="$attrs" 传入内部组件 —— 这在创建高阶的组件时会非常有用。inheritAttrs
属性解释:如果你不希望组件的根元素继承特性,你可以在组件的选项中设置 inheritAttrs: false
可能不是很好理解,我们可以举个例子来验证一下。
# 在父组件 app.vue 中
<template> | |
<div> | |
<MyInput type="text" placeholder="输入用户名" v-model="state.text" /> | |
<MyInput type="password" placeholder="输入密码" v-model="state.pass" /> | |
</div> | |
</template> | |
<script setup> | |
import MyInput from "@/components/myInput.vue"; | |
import { reactive } from "vue"; | |
const state = reactive({ | |
text: "", | |
pass: "", | |
}); | |
</script> |
# 子组件 myInput.vue 设置 inheritAttrs: true(默认)
<template> | |
<div class="input"> | |
<input v-bind="$attrs" v-model="modelValue" /> | |
</div> | |
</template> | |
<script> | |
export default { | |
props: { | |
modelValue: [String, Number], | |
}, | |
}; | |
</script> |
# 子组件 myInput.vue 设置 inheritAttrs: false
<template> | |
<div class="input"> | |
<input v-bind="$attrs" v-model="modelValue"/> | |
</div> | |
</template> | |
<script> | |
export default { | |
inheritAttrs: false, | |
props: { | |
modelValue: [String, Number], | |
}, | |
}; | |
</script> |
小结:
由上述例子可以看出,子组件的 props 中未注册父组件传递过来的属性。
- 当设置
inheritAttrs:true
时,子组件的顶层标签元素中会渲染出父组件传递过来的属性 (例如:type="text" 等) - 当设置
inheritAttrs: false
时,子组件的顶层标签元素中不会渲染出父组件传递过来的属性 - 不管
inheritAttrs
为 true 或者 false,子组件中都能通过 $attrs 属性获取到父组件中传递过来的属性。
# $attrs 和 inheritAttrs 实例
官网的文档简短而又不清晰,实在是看不懂,只好自己找代码验证来看看是什么意思:
<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Document</title> | |
<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.1.5/vue.global.js"></script> | |
</head> | |
<body> | |
<div id="app"> | |
<father :v1="'value1'" :v2="'value2'" :v3="'value3'"></father> | |
</div> | |
</body> | |
</html> | |
<script> | |
const app = Vue.createApp({ | |
data() { | |
return {} | |
}, | |
}) | |
app.component('father', { | |
// inheritAttrs: false, | |
props: ['v1'], | |
template: ` <div><p>v1 is </p> | |
<son v-bind='$attrs' :some="1"></son> | |
</div>`, | |
created() { | |
console.log('father:', this.$attrs) | |
} | |
}) | |
app.component('son', { | |
// inheritAttrs: false, | |
props: ['v2'], | |
template: `<div><p>v2 is </p> | |
<grandSon v-bind='$attrs'></grandSon> | |
</div>`, | |
created() { | |
console.log('son:', this.$attrs) | |
} | |
}) | |
app.component('grandSon', { | |
props: ['v3'], | |
template: `<p>v3 is </p>`, | |
created() { | |
console.log('grandSon:', this.$attrs) | |
} | |
}) | |
app.mount('#app') | |
</script> |
页面显示的结果:
v1 is value1
v2 is value2
v3 is value3
页面源代码:
<div id="app" data-v-app=""> | |
<div v2="value2" v3="value3"> <!-- 这是 father --> | |
<p>v1 is value1</p> | |
<div v3="value3" some="1"> <!-- 这是 son--> | |
<p>v2 is value2</p> | |
<p some="1">v3 is value3</p> <!-- 这是 grandSon --> | |
</div> | |
</div> | |
</div> |
控制台打印是当前组件的 $attrs:
father: Proxy
son: Proxy
grandSon: Proxy
首选,father 组件被传入了 3 个值,但是实际使用 props 接收的只有 v1,v2 和 v3 作为 attributes 在 DOM 里面渲染了。
上图的 devtool 也可以说明,另外就是控制台也同时证明了。
同样 son 组件只是接收 v2 作为 prop:
grandSon 组件只是接收 v3 作为 prop
father prop:v1,attributes: v2,v3
son prop:v2 ,attributes:v3,some
grandSon prop:v3,,attributes: some
发现无论是 father 传入的 3 个值 v1,v2,v3 还是 son 又传入的值 ':some=1',
只要不被 prop 传入下一层组件,那么一定是在下一层组件的 $attrs,也就是说不被作为 prop 的值会传入下一个组件作为 attrs 的一员。一个组件的 attrs 由父组件传递以及自己自带的组合而成。
上面说的是 $attrs, 那么 inheritAttrs 则说的是 attrs 继承,这里的继承是控制 DOM 渲染,不继承也就是不渲染了,但是实际还是存在这个 attrs 的。
inheritAttrs
属性默认是 true, 所以能看到上面的结论,attrs 会往下传,当设置为 false 的时候就不会在 DOM 渲染从上一层继承来的 attrs。
修改一下代码:
app.component('father', { | |
inheritAttrs: false, // 不继承 | |
props: ['v1'], | |
template: ` <div><p>v1 is </p> | |
<son v-bind='$attrs' :some="1"></son> | |
</div>`, | |
created() { | |
console.log('father:', this.$attrs) | |
} | |
}) |
father 组件这不继承 attrs,控制台的打印没变:
father: Proxy
son: Proxy
grandSon: Proxy
devtool 这里依然可以看到 attrs
但是看源代码:
<div id="app" data-v-app=""> | |
<div> <!-- 这里是 father --> <!-- 看这行 --> | |
<p>v1 is value1</p> | |
<div v3="value3" some="1"> <!-- 这里是 son--> | |
<p>v2 is value2</p> | |
<p some="1">v3 is value3</p> <!-- 这里是 grandSon--> | |
</div> | |
</div> | |
</div> |
DOM 渲染里面的 v2,v3 attrs 都不存在了。
所以综合总结一下:
$attrs
就是给组件传值排除了作为 prop 的那部分 (比如 father 的 v2,v3),包括了 (class,id)inheritAttrs
只是用来控制 attrs 是否在 DOM 中渲染。