事件处理与条件/列表渲染
约 1024 字大约 3 分钟
布欧-Lewyon
2026-05-15
首页 › Vue › Vue 基础 › 事件处理与条件/列表渲染
事件处理进阶
内联事件传参
<script>
export default {
methods: {
say(msg, event) {
alert(msg)
// event 是原生事件对象
},
warn(msg) {
alert(msg)
}
}
}
</script>
<template>
<!-- 传参 + 默认事件对象 -->
<button @click="say('你好', $event)">你好</button>
<!-- 直接传参 -->
<button @click="warn('不能点击')">已禁用</button>
</template>多事件处理
<template>
<!-- 逗号分隔多个事件处理器 -->
<button @click="handler1('a'), handler2('b')">点我</button>
</template>事件修饰符串联
<!-- 同时阻止默认行为 + 阻止冒泡 -->
<a @click.prevent.stop href="/api/logout">退出</a>
<!-- 仅当自身被点击时(不是子元素冒泡) -->
<div @click.self="handleDivClick">
<button @click="handleBtnClick">按钮</button>
</div>条件渲染
v-if / v-else-if / v-else
<script>
export default {
data: () => ({ score: 85 })
}
</script>
<template>
<p v-if="score >= 90">优秀</p>
<p v-else-if="score >= 70">良好</p>
<p v-else-if="score >= 60">及格</p>
<p v-else>不及格</p>
</template>v-show
v-show 始终渲染 DOM,仅切换 display:
<template>
<p v-show="isVisible">始终存在于 DOM 中</p>
</template>v-if vs v-show
| 对比 | v-if | v-show |
|---|---|---|
| 渲染机制 | 条件为假时不渲染 DOM | 始终渲染,仅切换 display |
| 切换成本 | 高(销毁/重建 DOM + 组件) | 低(仅修改 CSS) |
| 首次渲染 | 按条件决定是否渲染 | 始终渲染 |
| 适用场景 | 低频切换、初始为假 | 高频切换(tab 切换、弹窗) |
经验法则:运行时很少改变的场景用
v-if;需要频繁切换显示/隐藏的用v-show。
v-if 与 template
如果想同时对一组元素做条件判断而不额外加一层 <div>:
<template>
<template v-if="isAdmin">
<h2>管理面板</h2>
<p>只有管理员能看到此区域</p>
<button>删除用户</button>
</template>
</template>列表渲染
v-for 基础
<script>
export default {
data: () => ({
items: ['苹果', '香蕉', '橘子'],
users: [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' },
]
})
}
</script>
<template>
<!-- 遍历数组 -->
<ul>
<li v-for="(item, index) in items" :key="index">{{ index }}: {{ item }}</li>
</ul>
<!-- 遍历对象 -->
<ul>
<li v-for="(value, key, index) in { a: 1, b: 2 }" :key="key">
{{ index }}. {{ key }}: {{ value }}
</li>
</ul>
<!-- 遍历数字 -->
<span v-for="n in 10" :key="n">{{ n }} </span>
</template>:key 的重要性
<!-- ❌ 不用 key,或使用 index -->
<li v-for="(todo, index) in todos" :key="index">
{{ todo.text }}
</li>
<!-- ✅ 用唯一 ID -->
<li v-for="todo in todos" :key="todo.id">
{{ todo.text }}
</li>为什么 key 不能是 index? 列表中间插入一条时,插入点之后的所有元素 index 都变了 → Vue 无法复用已有 DOM,全部重建。 用稳定 ID 则 Vue 只需插入一条新 DOM,其余复用。
v-for 与 v-if
不要在同一元素上同时使用 v-for 和 v-if。Vue 3 中 v-if 优先级高于 v-for,不会像 Vue 2 那样先循环再判断。
<!-- ❌ 错误:v-if 无法访问 item -->
<li v-for="item in items" v-if="item.active" :key="item.id">
<!-- ✅ 方案一:在 <template> 上使用 v-for -->
<template v-for="item in items" :key="item.id">
<li v-if="item.active">{{ item.name }}</li>
</template>
<!-- ✅ 方案二:用计算属性过滤 -->
<li v-for="item in activeItems" :key="item.id">数组变更检测
Vue 3 可以检测以下变更(因为用 Proxy):
this.items.push('d') // ✅ 新增
this.items.pop() // ✅ 删除末尾
this.items.splice(1, 1, 'x') // ✅ 替换
this.items[2] = 'e' // ✅ Vue 3 支持
delete this.items[0] // ✅ Vue 3 支持
this.items.sort() // ✅v-model 表单绑定
基础用法
<script>
export default {
data: () => ({
text: '',
isChecked: false,
picked: '',
selected: '',
multiSelected: []
})
}
</script>
<template>
<input v-model="text" /> <!-- 文本 -->
<input type="checkbox" v-model="isChecked" /> <!-- 单个复选框 -->
<input type="radio" v-model="picked" value="A" /> <!-- 单选 -->
<select v-model="selected"> <!-- 下拉选择 -->
<option disabled value="">请选择</option>
<option>北京</option>
<option>上海</option>
</select>
</template>v-model 修饰符
<input v-model.trim="text" /> <!-- 自动去除首尾空格 -->
<input v-model.number="age" /> <!-- 自动转为数字 -->
<input v-model.lazy="text" /> <!-- 懒同步(change 事件而非 input 事件) -->小结
| 内容 | 关键点 |
|---|---|
v-if vs v-show | 低频切换用 v-if,高频切换用 v-show |
v-for 的 key | 始终用唯一 ID,不要用 index |
v-for + v-if | 用 template 包裹或计算属性过滤 |
| v-model 修饰符 | .trim、.number、.lazy |
上一节:Options API:响应式基础 下一节:Props 与 Emits
