数据绑定的一个常见需求场景是操纵元素的 CSS class 列表和内联样式。
因为 class
和 style
都是 attribute,我们可以和其他 attribute 一样使用 v-bind
将它们和动态的字符串绑定。
但是,在处理比较复杂的绑定时,通过拼接生成字符串是麻烦且易出错的。
因此,Vue 专门为 class
和 style
的 v-bind
用法提供了特殊的功能增强。
除了字符串外,表达式的值也可以是对象或数组。
能动态的修改各类样式
提要:
- v-bind:指令会将普通属性的值变为表达值
- 使用
v-bind
指令的class
属性值不再是字符串,而是表达式。 表达式里的className
不是一个普通的字符,而是一个变量,Vue
实例data
属性中的数据。 - v-bind 在处理 class 和 style 时, 表达式除了可以使用字符串之外,还可以是对象或数组。
- v-bind:class 可以简写为 :class。
v-bind
指令可以让我们将属性值关联到Vuedata
数据中,这样的属性,我们称作为属性的动态绑定。
属性的动态绑定比较符合vue以数据为驱动的模式,如果需要修改那个属性值,就可以直接通过修改Vue
数据即可。
注意:
动态属性绑定, 在我们需要的时候在使用,如果一个属性的是是固定的,并不会在未来发生改变,就没有必要动态绑定属性.
但在属性动态绑定过程中有两个属性比较特殊,这两个属性就是class 和style属性,
在将 v-bind
用于 class
和 style
时,Vue.js 做了专门的增强。
表达式结果的类型除了字符串之外,还可以是对象或数组。
用法示例
<h2 :class="msg">Hello World</h2>
使用动态绑定指令, 那么此时class后面的引号不再是字符串,而是一个JavaScript
表达式。
msg
也就成为了一个变量,因此此时h2标签的类名不是字符串msg
, 而是data数据中msg
中的值、
演示代码
<script src="https://unpkg.com/vue@next"></script>
<div id="app">
<!-- 未使用动态绑定的class属性 -->
<div class="msg">hello world</div>
<!-- 使用v-bind 动态绑定class属性 -->
<div :class="msg">你好! Vue</div>
</div>
<script>
const App = {
data() {
return {
msg: 'nbox',
}
},
}
const app = Vue.createApp(App);
app.mount("#app");
</script>
<style>
.nbox {
color: red;
}
</style>
浏览器执行效果

💛Class
属性绑定
我们可以为 v-bind:class 设置一个对象,从而动态的切换 class:
<div :class="{ 'active': isActive }"></div>
如果isActive为真,则在浏览器中渲染如下
<div class="active"></div>
语法说明:
- 上面的语法表示:
active
这个 类名是否存在 将取决于数据属性isActive
的 布尔特性。 - 如果
isActive
的值为true
, 那么div
将有类名active
否则,div
没有box
类名 - 需要注意,此时
active
就是一个类名,并不是vue中的数据属性
多个对象
<div :class="{'active' : isActive, 'text-danger' : hasError}"></div>
浏览器渲染
<div class="active text-danger"></div>
与普通的 class 属性共存
<div class="static" :class="{ 'active' : isActive, 'text-danger' : hasError }"> </div>
浏览器渲染
<div class="static active text-danger"></div>
错误示例,下列两个代码不会生效
<h2 :class="msg box">Hello World</h2>
<h2
:class="isTrue ? msg : ''"
:class="flag ? 'haha' : ''"
>你好</h2>
class绑定对象
如果您的class属性较多,我推荐您绑定对象,以便您的操作和代码的整洁性
<div id="app">
<div :class="classObject"></div>
</div>
const app = {
data() {
return {
classObject: {
'active': false,
'text-danger': true
}
}
}
}
浏览器渲染
<div class="text-danger"></div>
绑定一个返回对象的计算属性。这是一个常用且强大的模式
<div id="app">
<div :class="classObject"></div>
</div>
const app = {
data() {
return {
isActive: true,
error: false,
}
},
computed: {
classObject() {
return {
active: this.isActive,
'text-danger': !this.error,
}
}
}
}
浏览器渲染
<div class="active text-danger"></div>
class绑定数组(方法一)
<div id="app">
<div class="static" :class="[activeClass, errorClass]"></div>
</div>
const app = {
data() {
return {
activeClass: 'active',
errorClass: 'text-danger'
}
}
}
class绑定数组(方法二)
<div :class="classObject"></div>
const App = {
data() {
return {
classObject: ["static", "active", { "text-danger": true }],
}
},
}
以上两种方法,浏览器渲染均为
<div class="static active text-danger"></div>
使用三元表达式来切换列表中的 class
<div id="app">
<div :class="[isActive ? activeClass : '', errorClass]"></div>
</div>
const app = {
data() {
return {
isActive: false,
activeClass: 'active',
errorClass: 'text-danger'
}
}
}
浏览器渲染为
<div class="text-danger"></div>
在代码isActive ? activeClass : ''
中,因为isActive
是假,表达式的值为第三个,为空值,当isActive
为真时,表达式的值为第二个,即为activeClass
。
💛style(内联样式)
动态绑定style属性说明:
- 如果使用动态绑定属性方法绑定行内样式,那么style属性值将不再是字符串,而是表达式,
- 动态绑定style的值既然是表达式,那么就可以在表达式中使用对象.
- 如果值为对象,那么对象的属性名则为CSS样式属性, 值为样式的值。
- 注意,此时对象中的属性值,可以是确定的样式值,也可以是vue的数据变量,
- 因此有些值不能再像
style
标签中一样书写,例如50px
,以前使用不加引号,现在必须加引号
对象写法关于值的问题
如果使用动态绑定属性style里的对象值不加引号, 就会有如下的问题:
<h2 :style="{color:red,font-size:30px}">Hello World</h2>
上面的这种写法就会报错, red
和30px
会被当做变量去Vue data
属性中找对应的数据, 但是找不到就报错
正确的写法应该是这样的
<h2 :style="{color:'red',fontSize:'30px'}">Hello World</h2>
也能正确显示结果, 但是要注意字符串嵌套问题

对象写法的属性问题:
相信通过刚才的例子,你也发现了,我们发font-size
的写法改为了fontSize
.
因为CSS 属性名可以用驼峰式 (camelCase) 或短横线分隔 (kebab-case) 都可以:
因此,在普通的style
属性中一下两种写法都可以
<!-- 驼峰式 (camelCase) 写法 --->
<h2 style="color:red;fontSize:30px;">Hello World</h2>
<!-- 短横线分隔 (kebab-case --->
<h2 style="color:red;font-size:30px;">Hello World</h2>
两种处理方法:
- 驼峰式 (camelCase)
- 如果要使用连字符, 就需要添加双引号, 将属性变成字符串的写法
因此动态绑定需要如下写法
<!-- 驼峰式 (camelCase) 写法 --->
<h2 :style="{color:'red', fontSize:'30px'}">Hello World</h2>
<!-- 短横线分隔 (kebab-case) 但是要加引号 --->
<h2 :style="{color:'red', 'font-size' :'30px'}">Hello World</h2>
推荐用驼峰写法, 对象的值也可以是变量
示例代码
<div id="app">
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }">菜鸟教程</div>
</div>
<script>
const app = {
data() {
return {
activeColor: 'red',
fontSize: 30
}
}
}
Vue.createApp(app).mount('#app')
</script>
浏览器渲染
<div style="color: red; font-size: 30px;">菜鸟教程</div>
style绑定对象(推荐)
代码
<div id="app">
<div :style="styleObject">菜鸟教程</div>
</div>
<script>
const app = {
data() {
return {
styleObject: {
color: "red",
fontSize: "30px"
}
}
}
}
Vue.createApp(app).mount('#app')
浏览器渲染
<div style="color: red; font-size: 30px;">菜鸟教程</div>
同样的,如果样式对象需要更复杂的逻辑,也可以使用返回样式对象的计算属性。
动态修改样式
代码
<script src="https://unpkg.com/vue@next"></script>
<div id="app">
<h2 :style="styleObject">Hello World</h2>
<button @click="changColor">点击切换颜色</button>
</div>
<script>
const App = {
data() {
return {
styleObject: {
color: "red",
fontSize: "30px"
}
}
},
methods: {
changColor() {
this.styleObject.color = this.styleObject.color == "red" ? "skyblue" : "red"
}
}
}
const app = Vue.createApp(App);
app.mount("#app");
</script>
浏览器运行效果
Hello World
style绑定数组
可以扩展对象的用法,给动态属性的值绑定为数组,数组中就可以使用多组样式对象来绑定CSS样式。
这些对象会被合并后渲染到同一元素上:
代码
<div id="app">
<div :style="[baseStyles, overridingStyles]">菜鸟教程</div>
</div>
<script>
const app = {
data() {
return {
baseStyles: {
color: 'green',
fontSize: '30px'
},
overridingStyles: {
'font-weight': 'bold'
}
}
}
}
Vue.createApp(app).mount('#app')
浏览器渲染
<div style="color: green; font-size: 30px; font-weight: bold;">菜鸟教程</div>
注意:
当 v-bind:style 使用需要特定前缀的 CSS 属性时,如 transform ,Vue.js 会自动侦测并添加相应的前缀。
自动前缀
当你在 :style
中使用了需要浏览器特殊前缀的 CSS 属性时,Vue 会自动为他们加上相应的前缀。Vue 是在运行时检查该属性是否支持在当前浏览器中使用。如果浏览器不支持某个属性,那么将测试加上各个浏览器特殊前缀,以找到哪一个是被支持的。
多重值
可以为 style 绑定中的 property 提供一个包含多个值的数组,常用于提供多个带前缀的值,例如:
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
这样写只会渲染数组中最后一个被浏览器支持的值。在本例中,如果浏览器支持不带浏览器前缀的 flexbox,那么就只会渲染 display: flex。
💛组件
单个根元素的自定义组件
当你在带有单个根元素的自定义组件上使用 class 属性时,这些 class 将被添加到该元素中。此元素上的现有 class 将不会被覆盖。
<div id="app">
<runoob class="classC classD"></runoob>
</div>
app.component('runoob', {
template: '<h1 class="classA classB">I like runoob!</h1>'
})
浏览器渲染
<h1 class="classA classB classC classD">I like runoob!</h1>
带数据绑定,此元素上的现有 class 将不会被覆盖。
<my-component :class="{ active: isActive }"></my-component>
渲染(isActive
为真)
<p class="active">Hi</p>
多个根元素
如果你的组件有多个根元素,你需要定义哪些部分将接收这个类。可以使用 $attrs 组件属性执行此操作:
<script src="https://unpkg.com/vue@next"></script>
<style>
.classA {
color: red;
font-size:30px;
}
</style>
<div id="app">
<runoob class="classA"></runoob>
</div>
<script>
const app = Vue.createApp({})
app.component('runoob', {
template: `
<p :class="$attrs.class">I like runoob!</p>
<span>这是一个子组件</span>
`
})
app.mount('#app')
</script>
注意:template 中 ` 是反引号,不是单引号 '。
浏览器渲染
<div id="app">
<p class="classA">I like runoob!</p>
<span>这是一个子组件</span></div>
拓展想象
若是配合CSS变量,岂不是有无限可能