Vue 模板语法——属性绑定(2)

145 阅读3分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

1. 绑定 class 属性

开发中,我们经常需要根据不同情况给元素设置不同的 class,因为不同的 class 可以呈现不同的效果,比如:

  • 当数据为某个状态时,字体显示为红色;
  • 当数据为另一个状态时,字体显示为黑色;

所以很多时候我们需要根据不同的数据来动态决定元素的 class。因此,我们可以使用 v-bind 来动态绑定 class 属性。

可以使用结果的类型是字符串的表达式绑定 class

<p :class="className">{{ message }}</p>

但还有另外两种方式来绑定 class:对象或数组(表达式结果的类型是对象或数组)。

1.1. 对象语法

可以传给 :classv-bind:class 的简写)一个对象,以动态地切换 class

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

上面的语法表示 active 这个 class 是否存在将取决于数据属性 isActivetruthiness1,当数据属性 isActive 为真值时,则上面的 div 元素上将添加上 active 这个 class,否则,将不会添加上 active 这个 class

动态的 class:class 指令)也可以和普通的 class 属性共存,它们会进行合并,但不会做去重操作。比如有如下模板:

<div
  class="abc active"
  :class="{ active: isActive, classB: true, 'text-danger': hasError }"
>
  {{ message }}
</div>

和如下数据:

data() {
  return {
    message: '你好啊',
    isActive: true,
    hasError: false
  }
}

则渲染的结果为:

<div class="abc active active classB">你好啊</div>

绑定的对象可以不内联在模板里,我们可以将它抽取到一个组件实例的数据属性中,再绑定这个属性:

<div class="abc active" :class="classObj">{{ message }}</div>
data() {
  return {
    message: '你好啊',
    isActive: true,
    hasError: false,
    // 注意:因为 data() 返回的对象最终是要交给响应式系统处理的,所以它最好是一个纯对象,
    // 不应该让某个属性的值又去引用另一个属性的值,而是应该直接使用有关属性的初始值(比如这里的 
    // active: isActive、'text-danger': hasError,就应该把 isActive 换成它对应的值 true,
    // 把 hasError 换成它对应的值 false)
    classObj: {
      active: true,
      classB: true,
      'text-danger': false
    }
  }
}

完整代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    .active {
      color: red;
    }
  </style>
</head>
<body>
  <div id="app"></div>

  <template id="my-app">
    <!-- 1. 普通的绑定方式 -->
    <p :class="className">{{ message }}</p>
    <!-- 2. 对象绑定 -->
    <!-- 动态决定 class 是否添加,格式:{ 类名/[变量名]: 表达式/数据属性 } -->
    <p :class="{ aaa: true }"></p>
    <p :class="{ aaa: true && !'' }"></p>
    <p :class="{ [aaa]: true && !'' }"></p>
    <p :class="{ bbb: isActive }"></p>
    <!-- 小案例演示:点击按钮切换文本颜色 -->
    <div :class="{ active: isActive }">{{ message }}</div>
    <button @click="toggle">切换</button>
    <!-- 对象可以有多个键值对,所以可以在对象中动态绑定多个 class -->
    <div :class="{ active: isActive, classB: true, 'text-danger': hasError }">{{ message }}</div>
    <!-- 动态的 class 可以和普通的 class 属性共存,它们会进行合并,但不会做去重操作 -->
    <div
      class="abc active"
      :class="{ active: isActive, classB: true, 'text-danger': hasError }"
    >
      {{ message }}
    </div>
    <!-- 将对象抽取到一个数据属性中,绑定这个数据属性 -->
    <div class="abc active" :class="classObj">{{ message }}</div>
    <!-- 调用一个返回对象的方法,绑定其返回的对象(调用方法的方式不常用,computed 方式更常用) -->
    <div class="abc active" :class="getClassObj()">{{ message }}</div>
    <!-- 还可以绑定一个返回对象的计算属性(computed),这是一个常用且强大的模式,后面讲到 computed 时再说 -->
    
  </template>

  <script src="./js/vue.js"></script>
  <script>
    const App = {
      data() {
        return {
          message: '你好啊',
          className: 'class-a',
          aaa: 'ca',
          isActive: true,
          hasError: false,
          // 注意:因为 data() 返回的对象最终是要交给响应式系统处理的,所以它最好是一个纯对象,
          // 不应该让某个属性的值又去引用另一个属性的值,而是应该直接使用有关属性的初始值(比如这里的 
          // active: isActive、'text-danger': hasError,就应该把 isActive 换成它对应的值 true,
          // 把 hasError 换成它对应的值 false)
          classObj: {
            active: true,
            classB: true,
            'text-danger': false
          }
        }
      },
      methods: {
        toggle() {
          this.isActive = !this.isActive;
        },
        getClassObj() {
          return {
            active: true,
            classB: true,
            'text-danger': false
          };
        }
      },
      template: '#my-app'
    };

    Vue.createApp(App).mount('#app');
  </script>
</body>
</html>

1.2. 数组语法

我们可以把一个数组传给 :class,以应用一个 class 列表:

<div :class="['aaa', activeClass, errorClass]"></div>
data() {
  return {
    activeClass: 'active',
    errorClass: 'text-danger'
  }
}

渲染的结果为:

<div class="aaa active text-danger"></div>

数组中还可以使用三元表达式,以根据条件切换 class 或决定是否添加相应的 class

<div :class="['aaa', isActive ? 'active' : 'deactive']"></div>
<div :class="['aaa', isActive ? 'active' : '']"></div>
data() {
  return {
    isActive: true
  }
}

这样写将始终添加 aaa 这个 class,但只有在 isActive 为真值(truthy)时才添加 active 这个 class

数组中也可以使用对象语法:

<div :class="['aaa', { active: isActive }]"></div>

因此,当有多个条件 class(多个三元表达式)时,就可以使用对象语法进行简化了。

此外,数组中的 class 不会自动去重:

<div :class="['aaa', activeClass, errorClass, bbb]"></div>
data() {
  return {
    activeClass: 'active',
    errorClass: 'text-danger',
    bbb: 'aaa'
  }
}

渲染的结果为:

<div class="aaa active text-danger aaa"></div>

Footnotes

  1. 除了 false0-00n""nullundefinedNaN8 个值以外的值都是真值(truthy),只有这 8 个值是假值(falsy)。