第5章〓样式绑定 操作页面元素的 class 属性和 style 属性是数据绑定的一个常见的需求,开发者可以使用 vbind 来处理 class 属性和 style 属性。由于采用字符串拼接为属性赋值比较麻烦且容易出错,因此在Vue 3中可以使用对象或数组为属性赋值。 5.1绑定HTML样式 给页面元素设置 class 属性可以更改元素的样式,class 属性值指定样式表的类选择器。 5.1.1对象控制样式 开发者可以通过传给 vbind: class 一个对象,从而动态地切换 class 属性值,代码如下: <div v-bind:class="{ active: isActive }"></div> 上述代码表示 active 这个样式存在与否取决于 isActive 的值,可以通过以下代码来查看 isActive 值的改变对于样式的影响: <div id='app'> <div v-bind:class="{active:isActive}"></div> </div> <script> const app = { data() { return { isActive: true }; } }; const vm = Vue.createApp(app).mount('#app'); </script> 渲染结果如图5.1所示。 图5.1class属性绑定对象的渲染结果 在控制台中输入 vm.$data.isActive = false,可以看到页面发生改变,如图5.2所示。 图5.2isActive值改变为false后的页面变化 当isActive值为true时,active样式起作用,开发者可以在对象中传入更多字段来动态切换多个样式。此外,vbind: class指令也可以与普通的class属性共存,尝试修改如下模板和data代码: <div class="static" v-bind:class="{ active: isActive, 'text-danger': hasError }" ></div> data: { isActive: true, hasError: false } 渲染结果如图5.3所示。 图5.3vbind: class 指令与class 属性共存的渲染结果 当 isActive 或者 hasError 发生变化时,class属性的样式也会相应地更新,如将 hasError 的值设置为 true,则 class 属性的样式将变为“static active textdanger”。绑定的数据对象不必内联定义在模板中,如果绑定的数据对象比较复杂,可以在数据属性中单独定义一个对象进行绑定,代码如下: <div id="app"> <div v-bind:class="classObject "></div> </div> <script> const vm = Vue.createApp(() data() { return{ classObject: { active: true, 'text-danger': false } } } }) .mount('#app'); </script> 使用计算属性也可以实现动态更改样式,可以使用一个返回对象的计算属性进行绑定,代码如下: <div v-bind:class="classObject"></div> <script> const vm = Vue.createApp({ data() { return { isActive: true, error: null } }, computed: { classObject() { return { active: this.isActive && !this.error, 'text-danger': this.error && this.error.type === 'fatal' } } } }).mount('#app'); </script> 5.1.2数组控制样式 开发者可以将数组传给 vbind: class,这种方式将会在元素上应用一个样式列表,代码如下: <style> .active{ width:100px; height:100px; background:green; } .text-danger { background:red; } </style> <div v-bind:class="[activeClass, errorClass]"></div> <script> const vm = Vue.createApp({ data() { return { activeClass: 'active', errorClass: 'text-danger' } } }).mount('#app'); </script> 如果开发者想根据条件切换样式列表中的样式,可以使用三元表达式,代码如下: <div v-bind:class="[isActive?activeClass:'',errorClass]"></div> <script> const vm = Vue.createApp({ data() { return { activeClass: ' active', errorClass: 'text-danger', isActive: true } } }).mount('#app'); </script> 当有多个条件时上述写法有些烦琐,在数组语法中可以使用简化的对象语法,代码如下: <div v-bind:class="[{ active: isActive }, errorClass]"></div> 5.1.3在组件中的应用 在一个自定义单根元素组件上使用 class 属性时,会把相应样式添加到该组件的根元素上,而不会覆盖根元素上已有的样式,示例代码如下: Vue.component('my-component', { template: '<p class="foo bar">Hi</p>' }) <my-component class="baz boo"></my-component> <p class="foo bar baz boo">Hi</p> 对于带数据绑定的class属性同样适用,代码如下: <my-component v-bind:class="{ active: isActive }"></my-component> <p class="foo bar active">Hi</p> 如果组件有多个根元素,则需要通过使用 $attrs 组件属性来指定哪个根元素接收这个 class 属性,代码如下: <div id="app"> <my-component class="baz"></my-component> </div> <script> const app = Vue.createApp({}) app.component('my-component', { template: ' <p :class="$attrs.class">Hi!</p> <span>This is a child component</span> ' }) </script> 5.2绑定内联样式 使用 vbind: style 可以给元素绑定内联样式。 5.2.1对象描述样式 vbind: style 的对象语法非常直观,看起来非常像 CSS,但实际上是一个 JavaScript 对象。CSS 属性名可以使用驼峰式(camelCase)或短横线分隔(kebabcase)来命名,代码如下: <div id="app"> <div v-bind:style="{ color: activeColor, fontSize: fontSize + 'px' }"></div> </div> <script> const vm = Vue.createApp({ data() { return { activeColor: 'red', fontSize: 30 } } }).mount('#app'); </script> 如果直接使用对象字符串的方式设置CSS样式属性,那么代码冗长且可读性较差,可以在数据属性中定义一个样式对象,通过 vbind: style 绑定该对象让模板更清晰,代码如下: <div id="app"> <div v-bind:style="styleObject"></div> </div> <script> const vm = Vue.createApp({ data() { return { styleObject: { color: 'red', fontSize: '13px' } } } }).mount('#app'); </script> 5.2.2数组描述样式 vbind: style 的数组语法可以将多个样式对象应用到同一个元素上,代码如下: <div id="app"> <div v-bind:style="[baseStyles,moreStyles]"></div> </div> <script> const vm = Vue.createApp({ data() { return { baseStyles: { border: 'solid 2px black' }, moreStyles: { width: '100px', height: '100px', background: 'orange', } } } }).mount('#app'); </script> 5.2.3自动添加前缀 当 vbind: style 使用需要添加浏览器引擎前缀的 CSS 属性时,Vue 3 会自动侦测并添加相应的前缀,结果如下所示: transform:rotate(7deg); -ms-transform:rotate(7deg); // IE 9 -moz-transform:rotate(7deg); //Firefox -webkit-transform:rotate(7deg); //Safari 和 Chrome -o-transform:rotate(7deg); // Opera 5.2.4多重值样式 可以为绑定的 style 属性赋一个包含多个带前缀值的数组,这样写只会渲染数组中最后一个被浏览器支持的值。对于以下代码: <div :style="{display:['-webkit-box','-ms-flexbox','flex']}"></div> 如果浏览器支持不带浏览器前缀的 flexbox,那么就只会渲染 display: flex。 视频讲解 5.3实例: 实现列表的奇偶行不同样式 在工程项目中经常需要使用表格来展示多行数据。当表格行数较多时,为了让用户能够区分不同的行,通常会针对奇偶行应用不同的样式,这样用户可以更加清晰地查看数据。 本例定义了一个针对偶数行的样式规则,代码如下: .even { background-color: #cdedcd; } 表格数据采用vfor循环输出,vfor可以带一个索引参数,根据这个索引参数判断奇偶行。循环索引从0开始,对应的是第1行,为了方便判断,将其加1后再进行判断。判断规则为(index+1)%2===0,使用vbind: class 的对象语法,当该表达式值为true时,应用样式 even,完整代码如下所示: <div id="app" v-cloak> <table> <tr> <th>序号</th> <th>课程</th> <th>教师</th> <th>课时</th> <th>操作</th> </tr> <tr v-for="(book, index) in books" :key="book. id" :class="{even:(index+1)%2===0}"> <td>{{book.id}}</td> <td>{{book.title}}</td> <td>{{book.teacher}}</td> <td>{{book.classHour}}</td> <td> <button @click="deleteItem(index)">删除</button> </td> </tr> </table> </div> <script> const vm = Vue.createApp({ data() { return { books: [ { id: 1, title: '高等数学', teacher: '王老师', classHour: 32 }, { id: 2, title: 'VC++', teacher: '李老师', classHour: 8 }, { id: 3, title: '英语', teacher: '孙老师', classHour: 16 }, { id: 4, title: 'Web开发基础', teacher: '王老师', classHour: 16 } ] } }, methods: { deleteItem(index) { this.books.splice(index, 1); } } }).mount('#app'); </script> 上述代码在浏览器中的渲染结果如图5.4所示。 图5.4列表的奇偶行不同的渲染结果 5.4本章小结 本章介绍了 class 属性与 style 属性的绑定,开发者在使用 CSS 样式时可以拥有更多的选择和更灵活的处理方式。 习题 1. Vue 3 中绑定样式的方式有哪几种?区别是什么? 2. 使用样式实现一个 loading 效果。