Npcink Blog
切换菜单

v-bind 动态绑定样式 - Vue3 新手基础教程

VUE 的动态绑定样式详解

本页目录21 节

数据绑定的一个常见需求场景是操纵元素的 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 指令可以让我们将属性值关联到 Vue data数据中,这样的属性,我们称作为属性的动态绑定。
属性的动态绑定比较符合 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>

浏览器执行效果

原网页中的可执行演示已停用,以下完整保留为静态 HTML 代码。

<script src="https://unpkg.com/vue@next"></script>
<div id="npp">
<!-- 未使用动态绑定的class属性 -->
<div class="msg">hello world</div>
<!-- 使用v-bind 动态绑定class属性 -->
<div :class="msg">你好! Vue</div>
</div>
<script>
const Npp = {
data() {
return {
msg: 'nbox',
}
},
}
const npp = Vue.createApp(Npp);
npp.mount("#npp");
</script>
<style>
.nbox {
color: red;
}
</style>

💛Class

属性绑定

我们可以为 v-bind:class 设置一个对象,从而动态的切换 class:

<div :class="{ 'active': isActive }"></div>

如果 isActive 为真,则在浏览器中渲染如下

<div class="active"></div>

语法说明:

  1. 上面的语法表示: active 这个 类名是否存在 将取决于数据属性isActive 的 布尔特性。
  2. 如果 isActive的值为true, 那么div 将有类名active 否则, div没有box类名
  3. 需要注意,此时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 属性说明:

  1. 如果使用动态绑定属性方法绑定行内样式,那么 style 属性值将不再是字符串,而是表达式,
  2. 动态绑定 style 的值既然是表达式,那么就可以在表达式中使用对象.
  3. 如果值为对象,那么对象的属性名则为 CSS 样式属性, 值为样式的值。
  4. 注意,此时对象中的属性值,可以是确定的样式值,也可以是 vue 的数据变量,
  5. 因此有些值不能再像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>

两种处理方法:

  1. 驼峰式 (camelCase)
  2. 如果要使用连字符, 就需要添加双引号, 将属性变成字符串的写法

因此动态绑定需要如下写法

<!-- 驼峰式 (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>

浏览器运行效果

原网页中的可执行演示已停用,以下完整保留为静态 HTML 代码。

<script src="https://unpkg.com/vue@next"></script>
<div id="app">
<h3 :style="styleObject">Hello World</h3>
<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>

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>

原网页中的可执行演示已停用,以下完整保留为静态 HTML 代码。

<style>
.classA {
color: red;
font-size:30px;
}
</style>
<div id="qpp">
<runoob class="classA"></runoob>
</div>
<script>
const qpp = Vue.createApp({})
qpp.component('runoob', {
template: `
<p :class="$attrs.class">I like runoob!</p>
<span>这是一个子组件</span>
`
})
qpp.mount('#qpp')
</script>

拓展想象

若是配合 CSS 变量,岂不是有无限可能

参考文档