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-onlisteners 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
$attrsobject includes all attributes that are not declared by the component’spropsoremitsoptions (e.g.,class,style,v-onlisteners, etc.).
<span>Fallthrough attributes: {{ $attrs }}</span>
Notes
- 与 props 不同的是,fallthrough attributes 保留它们初始的 casing,so an attribute like
foo-barneeds to be accessed as$attrs['foo-bar']. - 一个
v-onevent 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-bindwithout 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)
}
}