Vue3 16.组件05 透传Attributes
Attributes继承
“透传 attribute”指的是传递给一个组件,却没有被该组件声明为props或emits的attribute或者v-on
事件监听器。最常见的例子就是class
、style
和id
。
当一个组件以单个元素为根作渲染时,透传的attribute会自动被添加到根元素上。举例:假如有一个<MyButton>
组件,它的模板为:
<!-- <MyButton>的模板 --> |
一个父组件使用了这个组件,并传入了class
:
<MyButton class="large" /> |
最后渲染出来的DOM结果是:
<button class="large">Click Me</button> |
这里,<MyButton>
并没有将class
声明为一个它所接受的prop,所以class
被视作透传attribute,自动透传到了<MyButton>
的根元素上。
对class
和style
的合并
如果一个子组件的根元素已经有了class
或者style
attribute,它会和从父组件上继承的值合并。如果将之前的模板改成这样:
<!-- <MyButton> 的模板 --> |
则最后渲染出的DOM结果会变为:
<button class="btn large">Click Me</button> |
v-on
监听器继承
同样的规则也适用于v-on
事件监听器:
<MyButton @click="onClick" /> |
click
监听器会被添加到<MyButton>
的根元素,即那个原生的<button>
元素之上。当原生的<button>
被点击,会触发父组件的onClick
方法。同样的,如果原生button
元素自身也通过v-on
绑定了一个事件监听器,则这个监听器和父组件继承的监听器都会被触发。
深层组件继承
有些情况下一个组件会在根节点上渲染另一个组件。比如重构一下<MyButton>
,让它在根节点上渲染<BaseButton>
:
<!-- <MyButton/> 的模板,只是渲染另一个组件 --> |
此时<MyButton>
接收的透传attribute会直接继续传给<BaseButton>
。
注意:
- 透传的attribute不会包含
<MyButton>
上声明的props或是针对emits
声明事件的v-on
监听函数。- 透传的attribute若符合声明,也可以作为props传入
<BaseButton>
禁用 Attributes 继承
如果不想要一个组件自动地继承attribute,可以在组件选项中设置inheritAttrs: false
。
从3.3版本开始可以直接在<script setup>
中使用defineOptions
:
<script setup> |
最常见的需要禁用attribute继承的场景就是attribute需要应用在根节点以外的其他元素上。通过设置inheritAttrs
选项为false
,可以完全控制透传进来的attribute被如何使用。
这些透传进来的attribute可以在模板的表达式中直接用$attrs
访问到。
<span>Fallthrough attribute: {{ $attrs }}</span> |
这个$attrs
对象包含了除组件所声明的props
和emits
之外的所有其他attribute,如class
,style
,v-on
监听器等等。
注意点⚠️:
- 和props有所不同,透传attributes在Javascript中保留了它们原始的大小写,所以像
foo-bar
这样的一个attribute需要通过$attrs['foo-bar']
来访问。- 像
@click
这样的一个v-on
事件监听器将在此对象下被暴露为一个函数$attrs.onClick
。
现在使用之前的<MyButton>
组件,有时候可能为了样式,需要在<button>
元素外包装一层<div>
:
<div class="btn-wrapper"> |
想要所有像class
和v-on
监听器这样的透传attribute都应用在内部的<button>
上而不是外层的<div>
上。可以通过设定inheritAttrs: false
和使用v-bind="$attrs"
来实现:
<div class="btn-wrapper"> |
多根节点的Attributes继承
和单根节点组件有所不同,有着多个根节点的组件没有自动attribute透传行为。如果$attrs
没有被显式绑定,将会抛出一个运行时警告。
<CustomLayout id="custom-layout" @click="changeValue" /> |
如果<CustomLayout>
有下面这样的多根节点模板,由于Vue不知道要将attribute透传到哪里,所以会抛出一个警告。
<header>...</header> |
如果$attrs
被显式绑定,则不会有警告:
<header>...</header> |
在Javascript中访问透传Attributes
如果需要,可以在<script setup>
中使用useAttrs()
API来访问一个组件的所有透传attribute:
<script setup> |
如果没有使用<script setup>
,attrs
会作为setup()
上下文对象的一个属性暴露:
export default { |
需要注意的是,虽然这里的attrs
对象总是反映为最新的透传attribute,但它并不是响应式的。不能通过监听器去监听它的变化。如果需要响应性,可以使用prop。或者也可以使用onUpdated()
使得在每次更新时结合最新的attrs
执行副作用。