Vue3 样式绑定语法详解与案例
一、样式绑定语法知识点
Vue3 提供了多种方式来绑定和操作元素的 class 和 style,以下是全部内容:
1. Class 绑定
(1) 对象语法
<div :class="{ active: isActive, 'text-danger': hasError }"></div>
(2) 数组语法
<div :class="[activeClass, errorClass]"></div>
(3) 三目运算符
<div :class="isActive ? 'active' : 'inactive'"></div>
(4) 绑定计算属性
<div :class="classObject"></div>
(5) 绑定组件上的 class
<my-component class="baz boo"></my-component>
<my-component :class="{ active: isActive }"></my-component>
2. Style 绑定
(1) 对象语法
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }"></div>
(2) 数组语法
<div :style="[baseStyles, overridingStyles]"></div>
(3) 自动前缀
Vue 会自动为需要浏览器前缀的 CSS 属性添加前缀
(4) 多重值
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }"></div>
二、详细案例代码
<template>
<div>
<!-- 1. 基本的 class 绑定 -->
<div
class="static"
:class="{ active: isActive, 'text-danger': hasError }"
>
基本 class 绑定 - 对象语法
</div>
<!-- 2. 数组语法绑定 class -->
<div :class="[activeClass, errorClass]">
数组语法绑定 class
</div>
<!-- 3. 条件表达式绑定 class -->
<div :class="isActive ? 'active' : 'inactive'">
条件表达式绑定 class
</div>
<!-- 4. 使用计算属性绑定 class -->
<div :class="classObject">
使用计算属性绑定 class
</div>
<!-- 5. 组件上的 class 绑定 -->
<my-component :class="{ active: isActive }"></my-component>
<!-- 6. 基本的 style 绑定 -->
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }">
基本的 style 绑定
</div>
<!-- 7. 数组语法绑定 style -->
<div :style="[baseStyles, overridingStyles]">
数组语法绑定 style
</div>
<!-- 8. 自动前缀示例 -->
<div :style="{ transform: 'rotate(30deg)' }">
自动前缀示例
</div>
<!-- 9. 多重值示例 -->
<div :style="{ display: ['-webkit-box', '-ms-flexbox', 'flex'] }">
多重值示例
</div>
<!-- 10. 动态切换样式 -->
<button @click="toggleActive">切换 active 状态</button>
<button @click="toggleError">切换 error 状态</button>
</div>
</template>
<script>
import { ref, computed } from 'vue';
import MyComponent from './MyComponent.vue';
export default {
components: {
MyComponent
},
setup() {
// 响应式数据
const isActive = ref(true);
const hasError = ref(false);
const activeColor = ref('red');
const fontSize = ref(16);
// class 相关数据
const activeClass = ref('active');
const errorClass = ref('text-danger');
// style 相关数据
const baseStyles = ref({
backgroundColor: 'lightblue',
padding: '10px'
});
const overridingStyles = ref({
color: 'white',
fontSize: '20px'
});
// 计算属性
const classObject = computed(() => ({
active: isActive.value && !hasError.value,
'text-danger': hasError.value
}));
// 方法
const toggleActive = () => {
isActive.value = !isActive.value;
};
const toggleError = () => {
hasError.value = !hasError.value;
};
return {
isActive,
hasError,
activeColor,
fontSize,
activeClass,
errorClass,
baseStyles,
overridingStyles,
classObject,
toggleActive,
toggleError
};
}
};
</script>
<style>
.static {
font-weight: bold;
}
.active {
background-color: #4CAF50;
color: white;
padding: 10px;
margin: 5px 0;
}
.inactive {
background-color: #f44336;
color: white;
padding: 10px;
margin: 5px 0;
}
.text-danger {
border: 2px solid red;
}
</style>
三、组件中的样式绑定示例
<!-- MyComponent.vue -->
<template>
<div class="my-component" :class="$attrs.class">
<p>这是一个子组件</p>
<p :style="componentStyle">组件内部样式绑定</p>
</div>
</template>
<script>
import { computed } from 'vue';
export default {
setup() {
const componentStyle = computed(() => ({
fontStyle: 'italic',
fontWeight: 'bold'
}));
return {
componentStyle
};
}
};
</script>
<style scoped>
.my-component {
border: 1px solid #ccc;
padding: 20px;
margin: 10px 0;
}
</style>
四、完整案例代码
<template>
<div class="container">
<h1>Vue3 样式绑定案例演示</h1>
<!-- 1. 对象语法 - Class 绑定 -->
<div class="section">
<h2>1. 对象语法 - Class 绑定</h2>
<div
class="box"
:class="{ active: isActive, 'text-danger': hasError, 'text-success': isSuccess }"
>
对象语法示例 - 根据条件动态添加类
</div>
<button @click="toggleActive">切换激活状态</button>
<button @click="toggleError">切换错误状态</button>
<button @click="toggleSuccess">切换成功状态</button>
</div>
<!-- 2. 数组语法 - Class 绑定 -->
<div class="section">
<h2>2. 数组语法 - Class 绑定</h2>
<div
class="box"
:class="[activeClass, errorClass, sizeClass]"
>
数组语法示例 - 动态组合多个类
</div>
<button @click="changeTheme">切换主题</button>
<button @click="changeSize">切换大小</button>
</div>
<!-- 3. 对象语法 - Style 绑定 -->
<div class="section">
<h2>3. 对象语法 - Style 绑定</h2>
<div
class="box"
:style="{ color: textColor, fontSize: fontSize + 'px', backgroundColor: bgColor }"
>
对象语法样式绑定 - 动态改变内联样式
</div>
<button @click="changeColor">改变颜色</button>
<button @click="changeFontSize">改变字体大小</button>
<button @click="changeBackground">改变背景色</button>
</div>
<!-- 4. 数组语法 - Style 绑定 -->
<div class="section">
<h2>4. 数组语法 - Style 绑定</h2>
<div
class="box"
:style="[baseStyle, themeStyle]"
>
数组合并样式 - 基础样式 + 主题样式
</div>
<button @click="switchTheme">切换主题样式</button>
</div>
<!-- 5. 复杂绑定示例 -->
<div class="section">
<h2>5. 复杂绑定示例</h2>
<div
class="box complex-box"
:class="computedClass"
:style="computedStyle"
>
复杂绑定示例 - 结合计算属性和多种绑定方式
</div>
<div class="controls">
<button @click="isHighlighted = !isHighlighted">高亮切换</button>
<button @click="boxSize += 10">增大尺寸</button>
<button @click="boxSize = Math.max(50, boxSize - 10)">减小尺寸</button>
</div>
</div>
<!-- 6. 表单元素样式绑定 -->
<div class="section">
<h2>6. 表单元素样式绑定</h2>
<input
type="text"
v-model="inputValue"
:class="{
'input-valid': inputValue.length > 5,
'input-invalid': inputValue.length > 0 && inputValue.length <= 5
}"
placeholder="输入至少6个字符"
/>
<div class="input-status">
状态: {{ inputValue.length > 0 ? (inputValue.length > 5 ? '有效' : '无效') : '请输入内容' }}
</div>
</div>
<!-- 7. 列表项样式绑定 -->
<div class="section">
<h2>7. 列表项样式绑定</h2>
<ul class="todo-list">
<li
v-for="(item, index) in todoList"
:key="item.id"
:class="{
'todo-item': true,
'completed': item.completed,
'priority-high': item.priority === 'high',
'priority-medium': item.priority === 'medium',
'priority-low': item.priority === 'low'
}"
@click="toggleTodo(index)"
>
<span class="todo-text">{{ item.text }}</span>
<span class="todo-priority">[{{ item.priority }}]</span>
</li>
</ul>
<button @click="addTodo">添加待办事项</button>
</div>
</div>
</template>
<script>
import { ref, reactive, computed } from 'vue'
export default {
name: 'StyleBindingDemo',
setup() {
// 1. 对象语法 - Class 绑定相关数据
const isActive = ref(false)
const hasError = ref(false)
const isSuccess = ref(false)
// 2. 数组语法 - Class 绑定相关数据
const activeClass = ref('primary-theme')
const errorClass = ref('bordered')
const sizeClass = ref('medium')
// 3. 对象语法 - Style 绑定相关数据
const textColor = ref('black')
const fontSize = ref(16)
const bgColor = ref('#f0f0f0')
// 4. 数组语法 - Style 绑定相关数据
const baseStyle = reactive({
padding: '20px',
margin: '10px 0',
border: '2px solid #ccc'
})
const themeStyle = ref({
backgroundColor: '#e3f2fd',
color: '#1976d2'
})
// 5. 复杂绑定示例数据
const isHighlighted = ref(false)
const boxSize = ref(100)
// 6. 表单元素样式绑定数据
const inputValue = ref('')
// 7. 列表项样式绑定数据
const todoList = ref([
{ id: 1, text: '学习Vue3', completed: false, priority: 'high' },
{ id: 2, text: '完成项目', completed: true, priority: 'medium' },
{ id: 3, text: '休息一下', completed: false, priority: 'low' }
])
// 计算属性 - 复杂class绑定
const computedClass = computed(() => {
return {
'highlighted': isHighlighted.value,
'large-box': boxSize.value > 80,
'small-box': boxSize.value <= 80
}
})
// 计算属性 - 复杂style绑定
const computedStyle = computed(() => {
return {
width: boxSize.value + 'px',
height: boxSize.value + 'px',
transition: 'all 0.3s ease'
}
})
// 方法定义
const toggleActive = () => {
isActive.value = !isActive.value
}
const toggleError = () => {
hasError.value = !hasError.value
}
const toggleSuccess = () => {
isSuccess.value = !isSuccess.value
}
const changeTheme = () => {
if (activeClass.value === 'primary-theme') {
activeClass.value = 'secondary-theme'
} else {
activeClass.value = 'primary-theme'
}
}
const changeSize = () => {
if (sizeClass.value === 'medium') {
sizeClass.value = 'large'
} else {
sizeClass.value = 'medium'
}
}
const changeColor = () => {
const colors = ['red', 'blue', 'green', 'purple', 'orange']
textColor.value = colors[Math.floor(Math.random() * colors.length)]
}
const changeFontSize = () => {
fontSize.value = fontSize.value === 16 ? 24 : 16
}
const changeBackground = () => {
const colors = ['#f0f0f0', '#e3f2fd', '#fff3e0', '#f3e5f5']
bgColor.value = colors[Math.floor(Math.random() * colors.length)]
}
const switchTheme = () => {
if (themeStyle.value.backgroundColor === '#e3f2fd') {
themeStyle.value = {
backgroundColor: '#fce4ec',
color: '#c2185b'
}
} else {
themeStyle.value = {
backgroundColor: '#e3f2fd',
color: '#1976d2'
}
}
}
const toggleTodo = (index) => {
todoList.value[index].completed = !todoList.value[index].completed
}
const addTodo = () => {
const priorities = ['high', 'medium', 'low']
const newTodo = {
id: Date.now(),
text: `新任务 ${todoList.value.length + 1}`,
completed: false,
priority: priorities[Math.floor(Math.random() * priorities.length)]
}
todoList.value.push(newTodo)
}
// 返回所有需要在模板中使用的数据和方法
return {
// Class 绑定相关
isActive,
hasError,
isSuccess,
activeClass,
errorClass,
sizeClass,
// Style 绑定相关
textColor,
fontSize,
bgColor,
baseStyle,
themeStyle,
// 复杂绑定相关
isHighlighted,
boxSize,
computedClass,
computedStyle,
// 表单相关
inputValue,
// 列表相关
todoList,
// 方法
toggleActive,
toggleError,
toggleSuccess,
changeTheme,
changeSize,
changeColor,
changeFontSize,
changeBackground,
switchTheme,
toggleTodo,
addTodo
}
}
}
</script>
<style scoped>
/* 容器样式 */
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
font-family: Arial, sans-serif;
}
/* 基础盒子样式 */
.box {
padding: 20px;
margin: 10px 0;
border: 1px solid #ddd;
border-radius: 4px;
background-color: white;
cursor: pointer;
transition: all 0.3s ease;
}
/* Section 样式 */
.section {
margin-bottom: 30px;
padding: 20px;
border: 1px solid #eee;
border-radius: 8px;
}
.section h2 {
margin-top: 0;
color: #333;
}
/* 按钮样式 */
button {
margin: 5px;
padding: 8px 16px;
background-color: #007bff;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 14px;
}
button:hover {
background-color: #0056b3;
}
/* Class 绑定相关样式 */
.active {
background-color: #d4edda !important;
border-color: #c3e6cb !important;
}
.text-danger {
color: #dc3545 !important;
}
.text-success {
color: #28a745 !important;
}
.primary-theme {
background-color: #007bff;
color: white;
}
.secondary-theme {
background-color: #6c757d;
color: white;
}
.bordered {
border: 3px solid #dc3545;
}
.medium {
font-size: 16px;
}
.large {
font-size: 20px;
}
/* 复杂绑定样式 */
.complex-box {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
}
.highlighted {
box-shadow: 0 0 15px rgba(255, 165, 0, 0.5);
border-color: orange;
}
.large-box {
font-weight: bold;
}
.small-box {
font-weight: normal;
}
/* 表单样式绑定 */
input {
padding: 10px;
border: 2px solid #ddd;
border-radius: 4px;
font-size: 16px;
margin-bottom: 10px;
width: 100%;
box-sizing: border-box;
}
.input-valid {
border-color: #28a745 !important;
background-color: #d4edda !important;
}
.input-invalid {
border-color: #dc3545 !important;
background-color: #f8d7da !important;
}
.input-status {
font-size: 14px;
color: #666;
}
/* 待办列表样式 */
.todo-list {
list-style: none;
padding: 0;
}
.todo-item {
padding: 15px;
margin: 5px 0;
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
display: flex;
justify-content: space-between;
align-items: center;
transition: all 0.2s ease;
}
.todo-item:hover {
background-color: #f8f9fa;
}
.completed {
background-color: #d4edda !important;
text-decoration: line-through;
color: #6c757d;
}
.priority-high {
border-left: 5px solid #dc3545;
}
.priority-medium {
border-left: 5px solid #ffc107;
}
.priority-low {
border-left: 5px solid #28a745;
}
.todo-priority {
font-size: 12px;
font-weight: bold;
text-transform: uppercase;
}
/* 控制按钮区域 */
.controls {
margin-top: 15px;
}
</style>
五、关键点说明
动态 class 绑定:
- 对象语法适合条件性的 class
- 数组语法适合同时应用多个 class
- 计算属性适合复杂的逻辑
动态 style 绑定:
- Vue 会自动为需要浏览器前缀的 CSS 属性添加前缀
- 推荐使用 camelCase (驼峰命名法) 来命名 CSS 属性
- 可以传递样式对象数组来合并多个样式对象
组件上的 class:
- 组件上的 class 会被自动应用到组件的根元素上
- 如果组件有多个根元素,需要使用
$attrs
手动绑定
性能考虑:
- 对于静态 class,直接使用 class 属性
- 对于动态 class,使用 :class 绑定
- 过度使用动态样式绑定可能会影响性能
样式作用域:
- 使用
<style scoped>
可以限制样式只作用于当前组件 - 深度选择器
::v-deep
可以影响子组件样式
- 使用