Vue: Fallthrough Attributes
2022-03-27
0. Intro
What is a Fallthrough Attribute?
“fallthrough attribute” 是一个 attribute 或者一个 v-on
event listener,它会被 pass to a component,但是它没有明确地在 receiving component 的 props 或者 emits 里面去定义。
Examples
- class
- style
- id
1. Attribute Inheritance
当 component 渲染一个 single root element 的时候,fallthrough attribute 会自动被加入到 root element 的 attribute 里面。
Example
Child
<!-- template of <MyButton> -->
<button>click me</button>
Parent
<MyButton class="large" />
Final rendered DOM - attribute from parent is inherited
<button class="large">click me</button>
class
and style
merging
假如 child compinent 的 root element 已经存在 class
或 style
attribute 了,那么它会与从 parent 继承来的 class
和 style
value 合并。
Example
Child:
<!-- template of <MyButton> -->
<button class="btn">click me</button>
Parent:
<MyButton class="large" />
Final Rendered DOM:
<button class="btn large">click me</button>
v-on
listener inheritance
同样地,v-on
event listener 的规则是:
Example
Parent:
<MyButton @click="onClick" />
这个 click
listener 会被加到 MyButton (child) 的 root element 上,也就是加到 native button
element 上。
当 native button
被点击时,它会触发 onClick
method of the parent component. 假如 native <button>
已经有一个与 v-on
绑定的 click
listener,那么两个 listener 都会被触发(类似 class 和 style 的merge)。
Nested Component Inheritance
当一个 component 把另一个 component 渲染为它的 root node,比如我们把 MyButton
重构为 render BaseButton
as root,而不是直接 render button
html:
<!-- template of <MyButton/> that simply renders another component -->
<BaseButton />
这种情况下, MyButton 接收到的 fallthrough attribute 就会自动被 forward 给 BaseButton
。
Note
- Forwarded attributes do not include any attributes that are declared as props, or
v-on
listeners of declared events by<MyButton>
- in other words, the declared props and listeners have been “consumed” by<MyButton>
.- Forwarded attributes may be accepted as props by
<BaseButton>
, if declared by it.
- Forwarded attributes 不包括被 MyButton 用掉的 props 和 listener。
- Forwarded attribute 可能被 BaseButton 作为 props 接收(假如 BaseButton 有声明)。
2. Disabling Attribute Inheritance
假如你不想自动继承的话,可以通过 inheritAttrs: false
in the component’s options 来 disable 这个功能。
常用情况
假如 attributes 需要被除了 root node 之外的其他 element 使用的话,我们常常会 set to false,这样就可以 take full control of where the fallthrough attributes should be applied.
如何 access fallthrough attributes?
可以用 $attrs
来获取以及直接在 template 里面使用。
The
$attrs
object includes all attributes that are not declared by the component’sprops
oremits
options (e.g.,class
,style
,v-on
listeners, etc.).
<span>Fallthrough attributes: {{ $attrs }}</span>
Notes
- 与 props 不同的是,fallthrough attributes 保留它们初始的 casing,so an attribute like
foo-bar
needs to be accessed as$attrs['foo-bar']
. - 一个
v-on
event listener(如@click
)会在 object 上被暴露为一个 function,比如$attrs.onClick
.
有时候需要 wrap extra div for styling purposes
<div class="btn-wrapper">
<button class="btn">click me</button>
</div>
如果想要 apply fallthrough attribute to inner element 怎么办?
假如我们不想让 div 去 inherit,而是让 button 去 inherit,就要用 inheritAttrs: false
and v-bind="$attrs"
。
不带 argument 的v-bind
会把 object 所有的 properties 都绑定为 target element 的 attributes。
<div class="btn-wrapper">
<button class="btn" v-bind="$attrs">click me</button>
</div>
Remember that
v-bind
without an argument binds all the properties of an object as attributes of the target element.
3. Attribute Inheritance on Multiple Root Nodes
假如一个 component 有多个 root node,那么就自动丧失 fallthrough behavior。如果我们没有明确地绑定 $attrs
,就会看到一个 runtime warning message。
Example
<CustomLayout id="custom-layout" @click="changeValue" />
If
<CustomLayout>
has the following multi-root template, there will be a warning because Vue cannot be sure where to apply the fallthrough attributes.
<header>...</header>
<main>...</main>
<footer>...</footer>
Fix - explicitly bind $attrs
<header>...</header>
<main v-bind="$attrs">...</main>
<footer>...</footer>
4. Accessing Fallthrough Attributes in JavaScript
如果需要的话,你也可以直接在 JS 里面通过 $attrs
去 access 这些 fallthrough attributes。
export default {
created() {
console.log(this.$attrs)
}
}