04Vue 3 类与样式绑定详解

Vue 3 提供了多种灵活的方式来操作元素的 class 和 style 绑定,让我们能够根据应用状态动态切换样式。

一、Class 绑定

1. 对象语法

<template>
  <!-- 根据 isActive 布尔值决定是否添加 active 类 -->
  <div :class="{ active: isActive, 'text-danger': hasError }"></div>
  
  <!-- 可以直接绑定一个对象 -->
  <div :class="classObject"></div>
</template>

<script setup>
import { reactive, computed } from 'vue'

const isActive = ref(true)
const hasError = ref(false)

// 响应式对象
const classObject = reactive({
  active: true,
  'text-danger': false
})

// 使用计算属性
const classObject = computed(() => ({
  active: isActive.value && !hasError.value,
  'text-danger': hasError.value && hasError.value.type === 'fatal'
}))
</script>

2. 数组语法

<template>
  <!-- 数组中可以包含字符串、对象和计算属性 -->
  <div :class="[activeClass, errorClass]"></div>
  <div :class="[isActive ? activeClass : '', errorClass]"></div>
  <div :class="[{ active: isActive }, errorClass]"></div>
</template>

<script setup>
const activeClass = ref('active')
const errorClass = ref('text-danger')
const isActive = ref(true)
</script>

3. 与普通 class 共存

<template>
  <!-- 静态 class 和动态 class 可以共存 -->
  <div class="static" :class="{ active: isActive, 'text-danger': hasError }"></div>
  <!-- 渲染结果:<div class="static active"></div> -->
</template>

4. 在组件上使用

<template>
  <!-- 子组件(MyComponent.vue) -->
  <div>
    <p :class="$attrs.class">子组件内容</p>
  </div>
</template>

<template>
  <!-- 父组件 -->
  <MyComponent class="my-class" />
</template>

二、Style 绑定

1. 对象语法

<template>
  <!-- 直接绑定样式对象 -->
  <div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
  
  <!-- 绑定样式对象变量 -->
  <div :style="styleObject"></div>
  
  <!-- 自动添加前缀(如 transform) -->
  <div :style="{ transform: 'scale(' + scale + ')' }"></div>
</template>

<script setup>
import { reactive } from 'vue'

const activeColor = ref('red')
const fontSize = ref(30)

// 样式对象
const styleObject = reactive({
  color: 'red',
  fontSize: '13px',
  fontWeight: 'bold'
})
</script>

2. 数组语法

<template>
  <!-- 合并多个样式对象 -->
  <div :style="[baseStyles, overridingStyles]"></div>
</template>

<script setup>
const baseStyles = reactive({
  color: 'black',
  fontSize: '14px'
})

const overridingStyles = reactive({
  color: 'red', // 会覆盖 baseStyles 中的 color
  fontWeight: 'bold'
})
</script>

3. 多重值

<template>
  <!-- 提供多个带前缀的值,Vue 只会渲染浏览器支持的最后一个 -->
  <div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
</template>

三、高级用法

1. 使用计算属性

<template>
  <div :class="computedClasses" :style="computedStyles"></div>
</template>

<script setup>
import { computed } from 'vue'

const isActive = ref(true)
const error = ref(null)

const computedClasses = computed(() => ({
  'btn': true,
  'btn-active': isActive.value,
  'btn-error': error.value !== null,
  'text-large': isActive.value && !error.value
}))

const computedStyles = computed(() => ({
  color: error.value ? 'red' : 'blue',
  fontSize: isActive.value ? '16px' : '14px',
  opacity: isActive.value ? 1 : 0.5
}))
</script>

2. 动态类名和样式名

<template>
  <!-- 动态属性名 -->
  <div :class="{[dynamicClassName]: true}"></div>
  <div :style="{[dynamicStyleName]: 'value'}"></div>
</template>

<script setup>
const dynamicClassName = ref('my-dynamic-class')
const dynamicStyleName = ref('margin-top')
</script>

3. CSS 模块支持

<template>
  <!-- 使用 CSS Modules -->
  <div :class="$style.myClass"></div>
  <div :class="[$style.myClass, $style.anotherClass]"></div>
</template>

<style module>
.myClass {
  color: red;
}
.anotherClass {
  font-size: 20px;
}
</style>

4. 自定义指令处理类/样式

<template>
  <div v-custom-class="{ active: isActive }"></div>
</template>

<script setup>
const vCustomClass = {
  mounted(el, binding) {
    const classes = binding.value
    Object.keys(classes).forEach(className => {
      if (classes[className]) {
        el.classList.add(className)
      } else {
        el.classList.remove(className)
      }
    })
  },
  updated(el, binding) {
    const classes = binding.value
    Object.keys(classes).forEach(className => {
      if (classes[className]) {
        el.classList.add(className)
      } else {
        el.classList.remove(className)
      }
    })
  }
}
</script>

四、最佳实践

1. 性能优化

<template>
  <!-- 避免在模板中写复杂逻辑 -->
  <!-- 不推荐 -->
  <div :class="{
    active: status === 'active' || isEnabled,
    error: hasError && attempts > 3
  }"></div>
  
  <!-- 推荐:使用计算属性 -->
  <div :class="statusClasses"></div>
</template>

<script setup>
import { computed } from 'vue'

const statusClasses = computed(() => ({
  active: status.value === 'active' || isEnabled.value,
  error: hasError.value && attempts.value > 3
}))
</script>

2. 组织样式类

<template>
  <!-- 使用有意义的类名组合 -->
  <button 
    :class="[
      'btn',
      `btn-${variant}`,
      `btn-${size}`,
      { 'btn-disabled': disabled }
    ]"
    :style="{
      '--custom-property': customValue
    }"
  >
    按钮
  </button>
</template>

<script setup>
const variant = ref('primary') // primary, secondary, danger
const size = ref('medium') // small, medium, large
const disabled = ref(false)
const customValue = ref('#ff0000')
</script>

3. 结合 CSS 变量

<template>
  <div 
    class="progress-bar"
    :style="{
      '--progress-width': `${progress}%`,
      '--progress-color': progressColor
    }"
  ></div>
</template>

<style scoped>
.progress-bar {
  width: 100%;
  height: 20px;
  background-color: #eee;
}
.progress-bar::before {
  content: '';
  display: block;
  width: var(--progress-width, 0%);
  height: 100%;
  background-color: var(--progress-color, #42b983);
  transition: width 0.3s ease;
}
</style>

五、TypeScript 支持

<template>
  <div :class="classObject" :style="styleObject"></div>
</template>

<script setup lang="ts">
import { computed, ref } from 'vue'

interface ClassObject {
  [key: string]: boolean
}

interface StyleObject {
  [key: string]: string | number
}

const isActive = ref<boolean>(true)
const progress = ref<number>(50)

const classObject = computed<ClassObject>(() => ({
  active: isActive.value,
  disabled: !isActive.value
}))

const styleObject = computed<StyleObject>(() => ({
  width: `${progress.value}%`,
  opacity: isActive.value ? 1 : 0.5
}))
</script>

总结

Vue 3 的类与样式绑定提供了:

  1. 灵活性:对象语法、数组语法多种方式

  2. 响应式:自动响应数据变化

  3. 性能优化:智能的更新机制

  4. 类型安全:完整的 TypeScript 支持

  5. CSS 集成:支持 CSS Modules、Scoped CSS

掌握这些绑定技巧,可以让你更高效地创建动态、响应式的用户界面。

posted @ 2026-02-10 14:22  麻辣~香锅  阅读(7)  评论(0)    收藏  举报