条件渲染与列表渲染
- 熟练使用
v-if/v-else/v-else-if与v-show控制元素显隐 - 使用
v-for遍历数组和对象,正确设置key - 理解
key的原理与最佳实践 - 掌握列表的增删操作(
push、filter)
1. 条件渲染
1.1 v-if / v-else / v-else-if
根据条件决定元素是否存在于 DOM 中 :条件为假时元素会被销毁 ,为真时重新创建。
基本用法:
vue
<script setup>
import { ref } from 'vue'
const score = ref(85)
</script>
<template>
<p v-if="score >= 90">优秀</p>
<p v-else-if="score >= 75">良好</p>
<p v-else-if="score >= 60">及格</p>
<p v-else>不及格</p>
</template>
注意:
v-else必须紧跟在带有v-if或v-else-if的元素之后,否则无效。- 判断规则:从上到下,命中第一个为真的条件即停止(所以条件顺序很重要,无需写冗余的范围限定)。
- 多个元素需同时控制时,使用
<template>包裹,v-if写在template上(<template>本身不会渲染到 DOM)。
vue
<template v-if="isLoggedIn">
<h2>欢迎回来</h2>
<button>退出登录</button>
</template>
1.2 v-show
v-show 也是控制显隐,但元素始终存在于 DOM 中 ,只是通过切换 display: none 来隐藏。
vue
<template>
<p v-show="isVip">会员专属内容</p>
</template>
限制 :不支持 v-else,不能用在 <template> 上。
1.3 选型指南
| 对比维度 | v-if |
v-show |
|---|---|---|
| 原理 | 条件假时元素销毁,真时重建 | 元素始终在 DOM,切 display |
| 初始渲染开销 | 假时无开销(不渲染) | 总是渲染,初始开销略大 |
| 切换开销 | 销毁+重建(较重) | 只改一个 CSS 属性(极轻) |
| 适用场景 | 很少切换(如登录状态、权限、空状态) | 频繁切换(如折叠面板、Tab页、加载中) |
选型口诀 :很少切换用
v-if,频繁切换用v-show。拿不准时优先
v-if(更省内存)。
2. 列表渲染
2.1 v-for 遍历数组
基本语法 :v-for="item in items" 或 v-for="(item, index) in items"(先 item,后 index,index 从 0 开始)
vue
<script setup>
import { ref } from 'vue'
const menus = ref(['仪表盘', '用户管理', '订单管理'])
</script>
<template>
<ul>
<li v-for="(menu, index) in menus" :key="menu">
{{ index + 1 }}. {{ menu }}
</li>
</ul>
</template>
数组内容变化(增删),列表自动随数据更新。
2.2 v-for 遍历对象
vue
<script setup>
const user = ref({ name: '张伟', role: '管理员', email:'zhangwei@example.com' })
</script>
<template>
<ul>
<li v-for="(value, key) in user" :key="key">{{ key }}:{{ value }}</li>
</ul>
</template>
参数顺序:
(value, key, index?),一般只用前两个。
2.3 禁止 v-if 与 v-for 同时使用
Vue3 中 v-if 优先级高于 v-for,写在同一个元素上会导致 v-if 无法获取到 v-for 的变量而报错。
错误示例:
vue
<li v-for="menu in menus" v-if="menu !== '系统设置'">{{ menu }}</li>
正确做法 :先用 computed 过滤数据,再循环:
vue
<script setup>
const visibleMenus = computed(() => menus.value.filter(m => m !== '系统设置'))
</script>
<template>
<li v-for="menu in visibleMenus" :key="menu">{{ menu }}</li>
</template>
3. key 的作用与选择
3.1 为什么需要 key?
key 是每个列表项的唯一标识,帮助 Vue 准确追踪每个节点的身份,从而在更新时高效复用或重建 DOM。
- 没有 key:Vue 按位置(index)对比更新,当列表顺序改变时可能复用错误的元素(导致状态错位)。
- 有唯一 key:Vue 能精确识别每个元素,无论顺序如何变化都能正确更新。
3.2 用 index 当 key 的陷阱
使用 :key="index" 时,如果列表中间插入或删除,新插入项的 index 会挤占原来的位置,Vue 会误以为"原来第一行的元素"还是第一行,导致内容更新但状态(如勾选、输入框内容)仍然留在原位,出现"串数据"的 bug。
原则 :只要列表会变化(增删排序),千万别用 index 作 key。
3.3 正确选 key 的方法
- 优先使用数据中唯一的业务 id (如
user.id、item.sku) - 若无现成 id,可在新增时手动生成一个唯一 id(如自增数值)
- 仅在列表永不变化(静态展示)时,可以用 index
4. 列表增删操作
4.1 新增:push()
js
const users = ref([...])
const addUser = () => {
users.value.push({
id: nextId++, // 保证唯一 key
name: '赵敏',
role: '编辑'
})
}
push 向响应式数组尾部添加元素,页面自动出现新行。
4.2 删除:filter()
js
const removeUser = (id) => {
// 返回不含该 id 的新数组,替换原数组
users.value = users.value.filter(user => user.id !== id)
}
filter返回新数组 (不修改原数组),显式赋值给users.value触发更新。- 不可只写
users.value.filter(...)而不赋值,否则原数组不变。
5. 常见问题排查
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| 菜单点击高亮不生效 | @click 与 :class 中使用的变量名不一致 |
确保 activeMenu === menu 两边完全一致 |
| 右侧内容一直不变 | v-else-if 条件写错或变量名拼写错误 |
检查 activeMenu === 'xxx' 的匹配字符串 |
| 列表不渲染 | v-for 放错位置 / 数据是空数组 |
v-for 写在要重复的元素上;检查数据是否为空 |
| 新增后页面没反应 | 漏写 .value 或 push 方法调用无效 |
确保 users.value.push(...) |
| 删除后列表没变 | filter 后未赋值 |
必须写成 users.value = users.value.filter(...) |
| 控制台报错"Cannot read properties..." | v-if 和 v-for 在同一元素 |
改用 computed 先过滤 |
| 列表增删后输入框/选框串位 | key 使用了 index |
把 :key="index" 改为数据的唯一 id |