Vue: Class and Style Bindings
2022-03-19
0. Intro
改变 element’s class and inline style 是一种常见的需要 data binding 的情况,因为 class 和 inline style 都是 html attributes,我们可以通过 v-bind
来完成这个任务,通过一些 expression calculation 来返回一个最终 string value 即可。
但是这么做的问题在于,string manipulation 容易发生错误,所以 vue 提供了一些额外的 api。
1. :class
API (short for v-bind:class
) - Binding to Objects
Example 1
<div :class="{ active: isActive }"></div>
active 是 css class name isActive 是 data property,通过 truthiness 来 toggle css class。
Example 2
我们可以在使用 :class 的同时继续使用 class attribute,两者会叠加。
<div
class="static"
:class="{ active: isActive, 'text-danger': hasError }"
></div>
Example 3
我们可以 create object 直接 pass 给 :class,不需要全部都写在 template 里面。
<div :class="classObject"></div>
data() {
return {
classObject: {
active: true,
'text-danger': false
}
}
}
Example 4
我们还可以用 computed property 来做 binding,这也是常见用法。
data() {
return {
isActive: true,
error: null
}
},
computed: {
classObject() {
return {
active: this.isActive && !this.error,
'text-danger': this.error && this.error.type === 'fatal'
}
}
}
2. Binding to Arrays
Example 1
data() {
return {
activeClass: 'active',
errorClass: 'text-danger'
}
}
<div :class="[activeClass, errorClass]"></div>
render:
<div class="active text-danger"></div>
Example 2
用 ternary expression 来 toggle class in the list.
expression evaluation is based on truthiness.
<div :class="[isActive ? activeClass : '', errorClass]"></div>
Example 3
我们也可以在 array 里面加 object,这样的写法看起来更简洁。
<div :class="[{ active: isActive }, errorClass]"></div>
3. With Components
Merging of the classes (Single root element)
When you use the class attribute on a component with a single root element, those classes will be added to the component’s root element, and merged with any existing class already on it.
Example 1
<!-- child component template -->
<p class="foo bar">Hi!</p>
<!-- when using the component -->
<my-component class="baz boo"></my-component>
结果:
<p class="foo bar baz boo">Hi</p>
Example 2
<!-- child component template -->
<p class="foo bar">Hi!</p>
<my-component :class="{ active: isActive }"></my-component>
结果(当 isActive 为 truthy):
<p class="foo bar active">Hi</p>
Merging of the classes (Multiple root elements)
If your component has multiple root elements, you would need to define which element will receive this class. You can do this using the $attrs
component property:
Example
这里只有 p 接收到了 class,span 没有接收到。
<!-- my-component template using $attrs -->
<p :class="$attrs.class">Hi!</p>
<span>This is a child component</span>
<my-component class="baz"></my-component>
结果:
<p class="baz">Hi!</p>
<span>This is a child component</span>
Related: component attribute inheritance
4. Binding Inline Styles v-bind:style
这个 :style
API 跟 :class
API 差不多,都支持 object 和 array,也通常会跟 computed property 一起使用。
Convention: Although camelCase keys are recommended, :style
also supports kebab-cased CSS property keys (corresponds to how they are used in actual CSS), e.g., <div :style="{ 'font-size': fontSize + 'px' }"></div>
Binding to Objects
Example 1
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
data() {
return {
activeColor: 'red',
fontSize: 30
}
}
Example 2
推荐使用 style object,而不是把逻辑都写在 template 里面。
<div :style="styleObject"></div>
data() {
return {
styleObject: {
color: 'red',
fontSize: '13px'
}
}
}
Example 3: Multiple Values
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
这种情况会根据 browser support 来确定 style。
This will only render the last value in the array which the browser supports. In this example, it will render display: flex
for browsers that support the unprefixed version of flexbox.
Auto-prefixing
When you use a CSS property that requires a vendor prefix in
:style
, Vue will automatically add the appropriate prefix. Vue does this by checking at runtime to see which style properties are supported in the current browser. If the browser doesn’t support a particular property then various prefixed variants will be tested to try to find one that is supported.
Binding to Arrays
Example 1
<div :style="[baseStyles, overridingStyles]"></div>