模式切换
指令
Vue 的指令(Directives)是带有 v-
前缀的特殊属性,用于动态操作 DOM。
v-bind(动态属性绑定)
作用
动态绑定 HTML 属性(如 id
、class
、style
)或组件 props
。
语法
html
<a v-bind:href="url">链接</a>
<!-- 简写(推荐) -->
<a :href="url">链接</a>
常见用法
绑定 class
html<div :class="{ active: isActive, 'text-danger': hasError }"></div>
javascriptdata() { return { isActive: true, hasError: false }; }
绑定 style
html<div :style="{ color: textColor, fontSize: size + 'px' }"></div>
绑定组件 props
html<ChildComponent :title="parentTitle" />
特点
- 属性值可以是动态变量或 JS 表达式。
- 简写方式
:
更简洁。
v-model(双向数据绑定)
作用
在表单输入元素(如 <input>
、<select>
)和组件上实现双向数据绑定。
语法
html
<input v-model="message" />
<!-- 等价于 -->
<input :value="message" @input="message = $event.target.value" />
v-model 基础用法
表单元素绑定
vue
<template>
<!-- 文本输入 -->
<input v-model="message" placeholder="请输入">
<p>输入的内容: {{ message }}</p>
<!-- 复选框 -->
<input type="checkbox" v-model="checked">
<p>复选框状态: {{ checked }}</p>
<!-- 单选按钮 -->
<input type="radio" value="A" v-model="picked">
<input type="radio" value="B" v-model="picked">
<p>选择的值: {{ picked }}</p>
<!-- 下拉选择 -->
<select v-model="selected">
<option value="apple">苹果</option>
<option value="banana">香蕉</option>
</select>
<p>选择的水果: {{ selected }}</p>
</template>
<script setup>
import { ref } from 'vue'
const message = ref('')
const checked = ref(false)
const picked = ref('A')
const selected = ref('apple')
</script>
组件绑定
vue
<CustomInput v-model="inputValue" />
<!-- 等价于 -->
<CustomInput
:modelValue="inputValue"
@update:modelValue="newValue => inputValue = newValue"
/>
内置修饰符
Vue 提供了以下常用修饰符:
.lazy
- 作用:将
input
事件改为change
事件 - 使用场景:避免输入时频繁更新,失去焦点时更新
vue
<input v-model.lazy="message">
<!-- 等价于 -->
<input :value="message" @change="message = $event.target.value">
.number
- 作用:自动将输入值转为数字类型
- 注意:如果转换失败会返回原始字符串
vue
<input v-model.number="age" type="number">
<script setup>
const age = ref(0) // 确保初始值是数字类型
</script>
.trim
- 作用:自动去除用户输入的首尾空格
vue
<input v-model.trim="username">
修饰符组合使用
可以同时使用多个修饰符:
vue
<input v-model.lazy.trim="searchText">
执行顺序:trim
→ number
(如果存在) → lazy
自定义组件的高级用法
多 v-model 绑定
Vue 3 支持在单个组件上绑定多个 v-model
:
vue
<UserName
v-model:first-name="firstName"
v-model:last-name="lastName"
/>
<!-- 等价于 -->
<UserName
:first-name="firstName"
@update:first-name="firstName = $event"
:last-name="lastName"
@update:last-name="lastName = $event"
/>
自定义修饰符
可以通过 modelModifiers
prop 实现自定义修饰符:
vue
<template>
<MyComponent v-model.capitalize="text" />
</template>
<script setup>
const text = ref('')
</script>
组件实现:
vue
<script setup>
const props = defineProps({
modelValue: String,
modelModifiers: { default: () => ({}) }
})
const emit = defineEmits(['update:modelValue'])
function emitValue(e) {
let value = e.target.value
if (props.modelModifiers.capitalize) {
value = value.charAt(0).toUpperCase() + value.slice(1)
}
emit('update:modelValue', value)
}
</script>
<template>
<input :value="modelValue" @input="emitValue" />
</template>
修饰符原理剖析
v-model
本质上是语法糖,编译后的代码:
vue
<input v-model="message">
<!-- 编译为 -->
<input
:value="message"
@input="message = $event.target.value"
>
当添加修饰符时:
vue
<input v-model.lazy.number="count">
<!-- 编译为 -->
<input
:value="count"
@change="count = Number($event.target.value)"
>
最佳实践
表单验证:结合
.lazy
减少验证频率vue<input v-model.lazy="email" @blur="validateEmail">
数字输入:始终使用
.number
配合type="number"
vue<input v-model.number="quantity" type="number" min="1">
性能优化:对大表单使用
.lazy
减少响应式更新移动端适配:在移动设备上考虑使用
.trim
避免键盘空格问题
常见问题
为什么 v-model.number 有时无效?
- 输入非数字字符时返回原始字符串
- 解决方案:配合
type="number"
并处理边界情况
如何阻止无效输入?
vue
<input
v-model="numberInput"
@keypress="isNumber($event)"
>
<script>
function isNumber(evt) {
const charCode = evt.keyCode || evt.which
if (charCode > 31 && (charCode < 48 || charCode > 57)) {
evt.preventDefault()
}
}
</script>
修饰符执行顺序
trim
:去除首尾空格number
:尝试转换为数字lazy
:改变触发事件
v-for(列表渲染)
作用
基于数组或对象循环渲染元素。
语法
html
<li v-for="(item, index) in items" :key="item.id">
{{ index }} - {{ item.name }}
</li>
关键点
必须指定
:key
- 提高 Diff 算法效率,避免渲染错误。
- 推荐使用唯一 ID(如
item.id
),而非index
。
遍历对象
html<div v-for="(value, key) in object" :key="key"> {{ key }}: {{ value }} </div>
范围迭代
html<span v-for="n in 10">{{ n }}</span> <!-- 1 到 10 -->
v-if / v-show(条件渲染)
v-if
- 特点:条件为
false
时,元素从 DOM 中移除。 - 适用场景:初始渲染条件较少变化时(如权限控制)。
html
<p v-if="isAdmin">管理员可见</p>
<p v-else-if="isUser">普通用户可见</p>
<p v-else>访客可见</p>
v-show
- 特点:通过
display: none
切换可见性,DOM 始终存在。 - 适用场景:频繁切换显示状态(如选项卡)。
html
<div v-show="isVisible">显示/隐藏内容</div>
对比
指令 | DOM 操作 | 初始渲染开销 | 切换开销 |
---|---|---|---|
v-if | 销毁/重建 | 低 | 高 |
v-show | display: none | 高(需渲染) | 低 |
v-on(事件绑定)
作用
监听 DOM 事件(如点击、输入)并执行方法。
语法
html
<button v-on:click="handleClick">点击</button>
<!-- 简写(推荐) -->
<button @click="handleClick">点击</button>
事件修饰符
修饰符 | 作用 | 示例 |
---|---|---|
.stop | 阻止事件冒泡 | @click.stop="doThis" |
.prevent | 阻止默认行为 | @submit.prevent="onSubmit" |
.once | 只触发一次 | @click.once="doThis" |
.native | 监听组件根元素原生事件 | <MyComponent @click.native="handleClick" /> |
按键修饰符
html
<input @keyup.enter="submit" /> <!-- 回车触发 -->
<input @keyup.esc="closeModal" /> <!-- ESC 键触发 -->
传递参数
html
<button @click="say('Hello')">打招呼</button>
<button @click="say('Hi', $event)">带事件对象</button>
javascript
methods: {
say(message, event) {
console.log(message, event);
}
}
其他常用指令
v-html
渲染原始 HTML(注意 XSS 风险):
html
<div v-html="rawHtml"></div>
v-slot
用于插槽作用域(缩写为 #
):
html
<template v-slot:header="slotProps">
{{ slotProps.user.name }}
</template>
<!-- 简写 -->
<template #header="{ user }">
{{ user.name }}
</template>
v-pre
跳过编译,直接输出原始内容:
html
<span v-pre>{{ 这里不会编译 }}</span> <!-- 输出 {{ 这里不会编译 }} -->
总结
指令 | 核心用途 | 关键注意点 |
---|---|---|
v-bind | 动态绑定属性 | 简写 : ,支持对象/数组语法 |
v-model | 表单双向绑定 | 修饰符:.lazy , .number , .trim |
v-for | 列表渲染 | 必须加 :key ,避免用 index |
v-if | 条件渲染(销毁 DOM) | 适合不频繁切换的场景 |
v-show | 条件渲染(CSS 隐藏) | 适合频繁切换 |
v-on | 事件绑定 | 简写 @ ,修饰符丰富 |