Skip to content

VueJS - 绑定

Vue 3 - 属性、Class、样式和表单绑定

Section titled “Vue 3 - 属性、Class、样式和表单绑定”

Vue 的数据绑定系统允许你声明式地将应用数据连接到 DOM。本章介绍如何在 Vue 3 中使用 v-bind 和 v-model 等指令来绑定 HTML 属性、Class、内联样式和表单输入。

你不能在 HTML 属性内部使用标准的 Mustache 语法 ({{ }})。相反,请使用 v-bind 指令或其简写形式 : 将属性绑定到 JavaScript 表达式或数据属性。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue 3 Attribute Binding</title>
<script src="https://unpkg.com/vue@3"></script>
</head>
<body>
<div id="app-attr">
<!-- 错误:将直接渲染 href="{{ googleLink }}" -->
<!-- <a href="{{ googleLink }}">Google (Incorrect)</a> -->
<!-- 正确:使用 v-bind -->
<a v-bind:href="googleLink" target="_blank">Google (v-bind)</a>
<br>
<!-- 正确:使用简写形式 : -->
<a :href="yahooLink" target="_blank">Yahoo (shorthand)</a>
<br>
<!-- 绑定元素的 ID -->
<p :id="paragraphId">This paragraph has a dynamic ID.</p>
<!-- 有条件地禁用按钮 -->
<button :disabled="isButtonDisabled">{{ isButtonDisabled ? 'Disabled' : 'Enabled' }}</button>
<button @click="toggleButton">Toggle Disable</button>
</div>
<script>
const { createApp, ref } = Vue;
createApp({
setup() {
const googleLink = ref('https://www.google.com');
const yahooLink = ref('https://www.yahoo.com');
const paragraphId = ref('my-unique-paragraph');
const isButtonDisabled = ref(false);
function toggleButton() {
isButtonDisabled.value = !isButtonDisabled.value;
}
return {
googleLink,
yahooLink,
paragraphId,
isButtonDisabled,
toggleButton
};
}
}).mount('#app-attr');
</script>
</body>
</html>

v-bind:href 或 :href 将锚点标签的 href 属性绑定到 googleLink 或 yahooLink 响应式变量的值。类似地,:id 绑定段落的 ID,而 :disabled 动态绑定按钮的禁用状态。

绑定 HTML Class (v-bind:class 或 :class)

Section titled “绑定 HTML Class (v-bind:class 或 :class)”

你可以通过将 :class 绑定到一个对象或数组来动态切换 Class。

绑定到一个对象,其中键是 Class 名称,值是布尔表达式,用于确定是否应应用该 Class。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue 3 Class Binding (Object)</title>
<script src="https://unpkg.com/vue@3"></script>
<style>
.active { background-color: lightgreen; font-weight: bold; }
.text-danger { color: red; }
.base-style { padding: 10px; border: 1px solid #ccc; margin-top: 10px; }
</style>
</head>
<body>
<div id="app-class-obj">
<div
class="base-style"
:class="{ active: isActive, 'text-danger': hasError }">
This div's classes change dynamically.
</div>
<button @click="isActive = !isActive">Toggle Active</button>
<button @click="hasError = !hasError">Toggle Error</button>
<!-- 也可以绑定到一个返回对象的 computed (计算属性) -->
<div class="base-style" :class="classObject">
Bound to computed object.
</div>
</div>
<script>
const { createApp, ref, computed } = Vue;
createApp({
setup() {
const isActive = ref(true);
const hasError = ref(false);
// 返回 Class 对象的 computed (计算属性)
const classObject = computed(() => ({
active: isActive.value,
'text-danger': hasError.value
// 你可以在这里添加更多静态或动态 Class
}));
return { isActive, hasError, classObject };
}
}).mount('#app-class-obj');
</script>
</body>
</html>

active Class 仅在 isActive 为 true 时应用,而 text-danger 仅在 hasError 为 true 时应用。请注意,text-danger 这样的 kebab-case 风格的 Class 名在对象键中需要使用引号。你可以混合使用静态(base-style)和动态 Class。

绑定到一个数组,其中包含 Class 名称(字符串)或对象(使用对象语法)。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue 3 Class Binding (Array)</title>
<script src="https://unpkg.com/vue@3"></script>
<style>
.active { background-color: lightblue; }
.important { font-weight: bold; border: 2px solid blue; }
.base { padding: 15px; margin-top: 10px; }
</style>
</head>
<body>
<div id="app-class-arr">
<div :class="['base', 'important', { active: isActive }]">
Mixing array and object syntax.
</div>
<button @click="isActive = !isActive">Toggle Active</button>
<!-- 绑定到一个返回数组的 computed (计算属性) -->
<div :class="classArray">
Bound to computed array.
</div>
</div>
<script>
const { createApp, ref, computed } = Vue;
createApp({
setup() {
const isActive = ref(false);
const activeClass = ref('active'); // 变量中的 Class 名称
const importantClass = ref('important');
const classArray = computed(() => [
'base',
importantClass.value, // 动态获取 Class 名称
isActive.value ? activeClass.value : '' // 条件 Class
]);
return { isActive, classArray };
}
}).mount('#app-class-arr');
</script>
</body>
</html>

这将始终应用 base 和 important Class,并根据 isActive 有条件地应用 active Class。你可以使用三元运算符或在数组中包含对象。

当在自定义组件上使用 :class 时,这些 Class 将被添加到组件的根元素上,并与根元素上已有的 Class 合并。

绑定内联样式 (v-bind:style 或 :style)

Section titled “绑定内联样式 (v-bind:style 或 :style)”

将 :style 绑定到一个对象或对象数组。

推荐使用对象语法。CSS 属性名可以使用 camelCase (驼峰式) 或 kebab-case (烤串式)(kebab-case 需要加引号)。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue 3 Style Binding (Object)</title>
<script src="https://unpkg.com/vue@3"></script>
</head>
<body>
<div id="app-style-obj">
<!-- 直接对象绑定 -->
<div :style="{ color: activeColor, fontSize: fontSize + 'px', 'margin-top': '10px' }">
Style bound directly.
</div>
<!-- 绑定到数据对象 -->
<div :style="styleObject">
Style bound to data object.
</div>
<label>Color:</label> <input v-model="activeColor">
<label>Font Size (px):</label> <input type="range" v-model="fontSize" min="10" max="40">
</div>
<script>
const { createApp, ref, computed } = Vue;
createApp({
setup() {
const activeColor = ref('blue');
const fontSize = ref(16);
// 返回样式对象的 computed (计算属性)
const styleObject = computed(() => ({
color: activeColor.value,
fontSize: `${fontSize.value}px` // 使用模板字符串
// backgroundColor: 'lightyellow' // 添加更多样式
}));
return { activeColor, fontSize, styleObject };
}
}).mount('#app-style-obj');
</script>
</body>
</html>

文本颜色和字体大小由 activeColor 和 fontSize 变量动态控制。

你可以将 :style 绑定到多个样式对象的数组。这在应用来自不同来源的样式时非常有用。

<div id="app-style-arr">
<div :style="[baseStyles, overrideStyles]">
Style bound to array of objects.
</div>
</div>
<script>
const { createApp, ref } = Vue;
createApp({
setup() {
const baseStyles = ref({
fontWeight: 'bold',
padding: '10px'
});
const overrideStyles = ref({
color: 'green',
border: '1px solid green'
});
return { baseStyles, overrideStyles };
}
}).mount('#app-style-arr');
</script>

overrideStyles 中的样式将与 baseStyles 中的样式合并,如果它们针对同一属性,则会覆盖 baseStyles 中的样式。

对于通过 :style 绑定的 CSS 属性,Vue 会在需要的地方自动添加供应商前缀(如 -webkit-)。

v-model 指令在表单输入元素(<input>、<textarea>、<select>)上创建双向数据绑定。它会根据输入类型自动选择更新元素的正确方式。

示例:文本输入、Textarea、复选框、单选按钮、Select

Section titled “示例:文本输入、Textarea、复选框、单选按钮、Select”
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Vue 3 v-model Example</title>
<script src="https://unpkg.com/vue@3"></script>
<style> form > div { margin-bottom: 15px; } label { margin-right: 10px; } </style>
</head>
<body>
<div id="app-v-model">
<form @submit.prevent>
<!-- 文本输入 -->
<div>
<label for="name">Name:</label>
<input type="text" id="name" v-model="formData.name" placeholder="Enter name">
<p>Entered Name: {{ formData.name }}</p>
</div>
<!-- 文本区域 -->
<div>
<label for="message">Message:</label>
<textarea id="message" v-model="formData.message" placeholder="Enter message"></textarea>
<p style="white-space: pre-line;">Entered Message: {{ formData.message }}</p>
</div>
<!-- 单个复选框 (布尔值) -->
<div>
<input type="checkbox" id="agree" v-model="formData.agreed">
<label for="agree">Agree to terms</label>
<p>Agreed: {{ formData.agreed }}</p>
</div>
<!-- 多个复选框 (数组) -->
<div>
<span>Interests:</span>
<input type="checkbox" id="tech" value="Technology" v-model="formData.interests">
<label for="tech">Technology</label>
<input type="checkbox" id="music" value="Music" v-model="formData.interests">
<label for="music">Music</label>
<input type="checkbox" id="sports" value="Sports" v-model="formData.interests">
<label for="sports">Sports</label>
<p>Selected Interests: {{ formData.interests }}</p>
</div>
<!-- 单选按钮 -->
<div>
<span>Favorite Color:</span>
<input type="radio" id="red" value="Red" v-model="formData.favoriteColor">
<label for="red">Red</label>
<input type="radio" id="green" value="Green" v-model="formData.favoriteColor">
<label for="green">Green</label>
<p>Selected Color: {{ formData.favoriteColor }}</p>
</div>
<!-- Select 下拉列表 -->
<div>
<label for="country">Country:</label>
<select id="country" v-model="formData.country">
<option disabled value="">Please select one</option>
<option>USA</option>
<option>Canada</option>
<option>Mexico</option>
</select>
<p>Selected Country: {{ formData.country }}</p>
</div>
<!-- Select 多选 (数组) -->
<div>
<label for="options">Options (Multiple):</label>
<select id="options" v-model="formData.selectedOptions" multiple>
<option value="A">Option A</option>
<option value="B">Option B</option>
<option value="C">Option C</option>
</select>
<p>Selected Options: {{ formData.selectedOptions }}</p>
</div>
</form>
</div>
<script>
const { createApp, reactive } = Vue;
createApp({
setup() {
const formData = reactive({
name: '',
message: '',
agreed: false,
interests: [], // 多个复选框对应的数组
favoriteColor: 'Red', // 初始单选选择
country: '', // 初始 Select 值
selectedOptions: [] // 多选 Select 对应的数组
});
return { formData };
}
}).mount('#app-v-model');
</script>
</body>
</html>
  • v-model 将表单元素的值与 formData 中对应的属性同步。
  • 对于文本输入和 textarea,它使用 value 属性和 input 事件。
  • 对于复选框,它使用 checked 属性和 change 事件。单个复选框绑定到布尔值,而多个 v-model 相同的复选框绑定到一个包含其 value 属性值的数组。
  • 对于单选按钮,它使用 checked 属性和 change 事件,绑定到被选中的单选按钮的 value 值。
  • 对于 Select 字段,它使用 value 和 change。单个 Select 绑定到被选中选项的 value 值。多选 Select 绑定到一个包含被选中选项 value 值的数组。

v-model 内置了一些修饰符:

  • .lazy: 在 change 事件后而非 input 事件后同步(例如,当输入框失去焦点时更新,而不是在每次按键时更新)。
  • .number: 自动将输入值类型转换为数字。如果值无法解析为数字,则返回原始值。
  • .trim: 自动去除用户输入的头尾空格。
<input v-model.lazy="message"> <!-- 输入框失去焦点时更新 -->
<input v-model.number="age" type="number"> <!-- 确保 age 是一个数字 -->
<input v-model.trim="username"> <!-- 移除头尾空格 -->

数据绑定是 Vue 的基石,它实现了应用状态与用户界面之间的无缝同步。