单向数据绑定是指数据只能从数据源流向视图,视图的变化不会直接影响数据源。
<template>
<div>
<p>{{ message }}</p> <!-- 单向绑定:数据 -> 视图 -->
</div>
</template>
<script>
export default {
data() {
return {
message: 'Hello Vue!'
}
}
}
</script>
<template>
<div>
<!-- 单向绑定属性 -->
<img :src="imageUrl" :alt="altText">
<a :href="linkUrl">{{ linkText }}</a>
<!-- 绑定样式 -->
<div :class="{ active: isActive }" :style="styles"></div>
<!-- 绑定属性 -->
<button :disabled="isDisabled">提交</button>
</div>
</template>
<script>
export default {
data() {
return {
imageUrl: '/path/to/image.jpg',
altText: '示例图片',
linkUrl: 'https://example.com',
linkText: '点击这里',
isActive: true,
styles: { color: 'red', fontSize: '14px' },
isDisabled: false
}
}
}
</script>
<template>
<div>
<p v-text="textContent"></p> <!-- 转义内容 -->
<div v-html="htmlContent"></div> <!-- 解析HTML,注意XSS风险 -->
</div>
</template>
<script>
export default {
data() {
return {
textContent: '<strong>文本内容</strong>', // 显示为字符串
htmlContent: '<strong>HTML内容</strong>' // 显示为加粗文本
}
}
}
</script>
双向数据绑定是指数据在数据源和视图之间双向流动,任何一方的变化都会同步到另一方。
<template>
<div>
<!-- 文本输入框 -->
<input v-model="username" placeholder="请输入用户名">
<p>用户名:{{ username }}</p>
<!-- 文本域 -->
<textarea v-model="description"></textarea>
<!-- 复选框 -->
<input type="checkbox" v-model="agree"> 同意协议
<input type="checkbox" v-model="hobbies" value="reading"> 阅读
<input type="checkbox" v-model="hobbies" value="sports"> 运动
<!-- 单选按钮 -->
<input type="radio" v-model="gender" value="male"> 男
<input type="radio" v-model="gender" value="female"> 女
<!-- 下拉选择框 -->
<select v-model="selectedCity">
<option value="">请选择</option>
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
</select>
</div>
</template>
<script>
export default {
data() {
return {
username: '',
description: '',
agree: false,
hobbies: [],
gender: '',
selectedCity: ''
}
}
}
</script>
<template>
<div>
<!-- .lazy:输入时不实时更新,失去焦点时更新 -->
<input v-model.lazy="lazyValue">
<!-- .number:自动转换为数字 -->
<input v-model.number="age" type="number">
<!-- .trim:自动去除首尾空格 -->
<input v-model.trim="trimmedValue">
<!-- 组合使用 -->
<input v-model.lazy.trim="combinedValue">
</div>
</template>
<!-- 父组件 -->
<template>
<div>
<CustomInput v-model="customValue" />
<p>父组件值:{{ customValue }}</p>
</div>
</template>
<script>
import CustomInput from './CustomInput.vue'
export default {
components: { CustomInput },
data() {
return {
customValue: ''
}
}
}
</script>
<!-- 子组件 CustomInput.vue -->
<template>
<input
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
>
</template>
<script>
export default {
props: ['modelValue'],
emits: ['update:modelValue']
}
</script>
v-model 本质上是语法糖,它结合了 v-bind 和 v-on:
<!-- 这是简写 -->
<input v-model="message">
<!-- 等同于 -->
<input
:value="message"
@input="message = $event.target.value"
>
<!-- 在自定义组件中 -->
<CustomInput v-model="value" />
<!-- 等同于 -->
<CustomInput
:model-value="value"
@update:model-value="value = $event"
/>
<template>
<UserForm
v-model:username="username"
v-model:email="email"
v-model:age="age"
/>
</template>
<script>
export default {
data() {
return {
username: '',
email: '',
age: null
}
}
}
</script>
<!-- 父组件 -->
<template>
<CustomInput v-model.capitalize="text" />
</template>
<!-- 子组件 -->
<template>
<input
:value="modelValue"
@input="emitValue($event.target.value)"
>
</template>
<script>
export default {
props: {
modelValue: String,
modelModifiers: {
default: () => ({})
}
},
emits: ['update:modelValue'],
methods: {
emitValue(value) {
if (this.modelModifiers.capitalize) {
value = value.charAt(0).toUpperCase() + value.slice(1)
}
this.$emit('update:modelValue', value)
}
}
}
</script>
| 绑定方式 | 语法 | 使用场景 | 特点 |
|---|---|---|---|
| 单向绑定 | {{ }}, v-bind, v-text, v-html |
显示数据、属性绑定、样式绑定 | 数据源到视图的单向流动,性能更好 |
| 双向绑定 | v-model |
表单输入、用户交互 | 视图和数据源双向同步,开发效率高 |
优先使用单向绑定
合理使用双向绑定
.sync(Vue 2)或多个 v-model(Vue 3)性能优化
<!-- 频繁更新的大列表,避免使用 v-model -->
<input :value="searchText" @input="handleSearch">
<!-- 使用防抖或节流 -->
<script>
import { debounce } from 'lodash'
export default {
methods: {
handleSearch: debounce(function(event) {
this.searchText = event.target.value
}, 300)
}
}
</script>
表单验证
<template>
<form @submit.prevent="handleSubmit">
<input
v-model="formData.email"
@blur="validateField('email')"
>
<span v-if="errors.email">{{ errors.email }}</span>
</form>
</template>
Vue 提供了灵活的数据绑定机制: