Vue 条件与循环渲染:v-if/v-else 与 v-for 的语法简介

在 Vue 开发中,条件渲染(v-if/v-else)和循环渲染(v-for)是最常用的模板语法,它们让我们能够根据数据动态控制 DOM 元素的显示与列表渲染。

接下来跟随我的脚步,一起来看看这两种语法的用法、区别。

一、条件渲染:v-if /v-else/v-else-if

条件渲染用于根据表达式的真假来动态显示或隐藏元素,Vue 提供了 v-ifv-elsev-else-if 三个指令实现这一功能。

1. 基本用法


<template> <div class="condition-example"> <!-- v-if:表达式为真时渲染 --> <p v-if="isVisible">这是 v-if 渲染的内容</p> <!-- v-else:与 v-if 搭配使用,当 v-if 为假时渲染 --> <p v-else>这是 v-else 渲染的内容</p> <!-- v-else-if:多条件判断 --> <div v-if="score >= 90">优秀</div> <div v-else-if="score >= 60">及格</div> <div v-else>不及格</div> </div> </template> <script setup> import { ref } from 'vue'; // 控制 v-if/v-else 的显示 const isVisible = ref(true); // 控制多条件判断 const score = ref(85); </script>

核心特点

  • v-if 是 “真正的条件渲染”—— 当条件为假时,元素会被完全从 DOM 中移除,而非仅隐藏;
  • v-else 和 v-else-if 必须紧跟在 v-if 或 v-else-if 后面,否则无法识别;
  • 条件表达式可以是任何返回布尔值的 JavaScript 表达式(如 score >= 90isLogin && hasPermission)。

2. v-if 与 v-show 的区别

Vue 还提供 v-show 指令用于条件显示,它与 v-if 的核心区别在于元素是否被移除


<template> <div> <!-- v-if:条件为假时元素被移除 --> <p v-if="isVisible">v-if 内容</p> <!-- v-show:条件为假时元素被隐藏(添加 display: none 样式) --> <p v-show="isVisible">v-show 内容</p> </div> </template>

特性v-ifv-show
渲染方式条件为真时才渲染元素始终渲染元素,通过样式控制显示 / 隐藏
DOM 操作会触发元素的创建 / 销毁仅修改样式,元素始终存在
初始渲染成本条件为假时,初始渲染成本低无论条件真假,初始渲染成本高
切换成本条件切换时,成本高(DOM 操作)切换成本低(仅修改样式)
适用场景条件很少切换(如权限判断)条件频繁切换(如标签页切换)

3. 条件渲染的最佳实践

(1)避免在同一元素上使用 v-if 和 v-for

Vue 官方明确建议不要在同一元素上同时使用 v-if 和 v-for,因为 v-for 的优先级高于 v-if,会导致性能问题(循环中每次都要判断条件)。

错误示例


<!-- 不推荐:v-for 和 v-if 同时使用 --> <ul> <li v-for="item in list" v-if="item.active" :key="item.id"> {{ item.name }} </li> </ul>

正确做法:先通过计算属性过滤数据,再循环渲染:


<template> <ul> <!-- 推荐:先过滤再循环 --> <li v-for="item in activeItems" :key="item.id"> {{ item.name }} </li> </ul> </template> <script> import { ref, computed } from 'vue'; const list = ref([ { id: 1, name: '选项1', active: true }, { id: 2, name: '选项2', active: false }, { id: 3, name: '选项3', active: true } ]); // 计算属性过滤数据 const activeItems = computed(() => { return list.value.filter(item => item.active); }); </script>

(2)使用 <template> 包裹多元素条件渲染

当需要条件渲染多个元素时,可使用 <template> 作为包裹容器(不会被渲染到 DOM 中):


<template> <!-- 使用 template 包裹多元素,避免额外 DOM 节点 --> <template v-if="hasPermission"> <h3>权限内容标题</h3> <p>这是需要权限才能查看的内容</p> <button>操作按钮</button> </template> </template>

(3)为条件渲染的元素添加 key 提升性能

当切换 v-if/v-else 时,Vue 可能会复用已有元素以优化性能。若需避免复用(如表单输入场景),可添加 key 标识:


<template> <div> <template v-if="isEditing"> <input type="text" key="edit-input" placeholder="编辑模式"> </template> <template v-else> <input type="text" key="view-input" placeholder="查看模式"> </template> <button @click="isEditing = !isEditing">切换模式</button> </div> </template> <script> import { ref } from 'vue'; const isEditing = ref(false); </script>

添加不同 key 后,切换模式时输入框会被重新创建,而非复用,避免输入内容意外保留。

二、循环渲染:v-for

v-for 用于基于数组或对象渲染列表,是处理动态数据列表的核心指令。

1. 基本用法

(1)遍历数组

<template> <ul> <!-- 基本用法:item 为数组元素 --> <li v-for="item in items" :key="item.id"> {{ item.name }} </li> <!-- 带索引:(item, index) 接收元素和索引 --> <li v-for="(item, index) in items" :key="item.id"> {{ index + 1 }}. {{ item.name }} </li> </ul> </template> <script> import { ref } from 'vue'; const items = ref([ { id: 1, name: '苹果' }, { id: 2, name: '香蕉' }, { id: 3, name: '橙子' } ]); </script>

(2)遍历对象

<template> <ul> <!-- 遍历对象:(value, key) 接收值和键名 --> <li v-for="(value, key) in user" :key="key"> {{ key }}: {{ value }} </li> <!-- 带索引:(value, key, index) 接收值、键名和索引 --> <li v-for="(value, key, index) in user" :key="key"> {{ index + 1 }}. {{ key }}: {{ value }} </li> </ul> </template> <script> import { reactive } from 'vue'; const user = reactive({ name: '张三', age: 20, gender: '男' }); </script>

(3)遍历整数

v-for 还可以直接遍历整数,用于渲染固定次数的元素:


<template> <div> <!-- 渲染 5 个星号 --> <span v-for="n in 5" :key="n">★</span> </div> </template>

2. key 属性的重要性

v-for 渲染列表时,必须为每个项添加唯一的 key 属性,这是 Vue 虚拟 DOM Diff 算法的关键,用于识别列表项的身份,优化渲染性能。


<!-- 正确:使用唯一 ID 作为 key --> <li v-for="item in items" :key="item.id"> {{ item.name }} </li>

为什么需要 key?
当列表数据变化时(如增删、排序),Vue 会通过 key 判断哪些元素是新增的、删除的或移动的,从而只更新变化的部分,而非重新渲染整个列表。

key 的选择原则

  • 优先使用数据本身的唯一标识(如后端返回的 id);
  • 避免使用索引(index)作为 key—— 当列表排序或删除中间项时,索引会变化,导致 key 失效,反而影响性能;
  • 若数据确实没有唯一标识,可使用 Symbol 或其他方式生成临时唯一 key。

3. 数组更新检测

Vue 对数组的一些方法进行了包裹,使得这些方法修改数组后会自动触发视图更新,这些方法被称为 “响应式数组方法”:

  • 修改原数组的方法(会触发更新):

    • push():添加元素到末尾
    • pop():删除末尾元素
    • shift():删除第一个元素
    • unshift():添加元素到开头
    • splice():添加 / 删除 / 替换元素
    • sort():排序
    • reverse():反转
  • 返回新数组的方法(需替换原数组才会触发更新):

    • filter()
    • concat()
    • slice()

<template> <div> <ul> <li v-for="item in fruits" :key="item.id">{{ item.name }}</li> </ul> <button @click="addFruit">添加水果</button> <button @click="filterFruits">筛选苹果</button> </div> </template> <script> import { ref } from 'vue'; const fruits = ref([ { id: 1, name: '苹果' }, { id: 2, name: '香蕉' }, { id: 3, name: '橙子' } ]); // 使用 push() 修改原数组(自动更新视图) const addFruit = () => { fruits.value.push({ id: 4, name: '草莓' }); }; // 使用 filter() 返回新数组(需替换原数组才更新视图) const filterFruits = () => { fruits.value = fruits.value.filter(item => item.name === '苹果'); }; </script>

注意:直接通过索引修改数组元素(如 fruits.value[0] = { ... })不会触发视图更新,需使用 splice 或替换整个数组:


// 错误:直接修改索引,不触发更新 fruits.value[0] = { id: 1, name: '红苹果' }; // 正确:使用 splice 修改 fruits.value.splice(0, 1, { id: 1, name: '红苹果' }); // 正确:替换整个数组 fruits.value = [...fruits.value.slice(0, 0), { id: 1, name: '红苹果' }, ...fruits.value.slice(1)];

4. 循环渲染的最佳实践

(1)始终指定 key 且确保唯一

如前所述,key 是优化列表渲染的关键,必须添加且确保唯一:


<!-- 推荐 --> <li v-for="item in products" :key="item.id"> {{ item.name }} </li> <!-- 不推荐:使用索引作为 key --> <li v-for="(item, index) in products" :key="index"> {{ item.name }} </li>

(2)避免在 v-for 中修改原数据

循环渲染时,应避免直接在模板中修改数组元素(如 v-for 内部使用 v-model 绑定元素属性),推荐通过方法统一处理:


<template> <ul> <li v-for="item in items" :key="item.id"> <input type="text" :value="item.name" @input="(e) => updateItemName(item.id, e.target.value)" > </li> </ul> </template> <script> import { ref } from 'vue'; const items = ref([ { id: 1, name: '商品1' }, { id: 2, name: '商品2' } ]); // 统一方法更新数据,逻辑更清晰 const updateItemName = (id, newName) => { const item = items.value.find(item => item.id === id); if (item) { item.name = newName; } }; </script>

(3)使用计算属性处理列表数据

当需要对列表进行过滤、排序等操作时,优先使用计算属性处理,而非在 v-for 中直接处理,提高代码可读性和性能:


<template> <div> <input v-model="searchText" placeholder="搜索商品"> <ul> <!-- 渲染过滤后的列表 --> <li v-for="item in filteredItems" :key="item.id"> {{ item.name }} </li> </ul> </div> </template> <script> import { ref, computed } from 'vue'; const items = ref([ { id: 1, name: '苹果手机' }, { id: 2, name: '华为平板' }, { id: 3, name: '小米手表' } ]); const searchText = ref(''); // 计算属性过滤数据 const filteredItems = computed(() => { return items.value.filter(item => item.name.toLowerCase().includes(searchText.value.toLowerCase()) ); }); </script>

(4)控制循环渲染的范围

对于大型列表(如 1000+ 项),直接全部渲染会导致性能问题,可采用 “分页” 或 “虚拟滚动” 优化:


<!-- 分页示例 --> <template> <div> <ul> <li v-for="item in currentPageItems" :key="item.id"> {{ item.name }} </li> </ul> <button @click="currentPage--" :disabled="currentPage === 1">上一页</button> <span>第 {{ currentPage }} 页</span> <button @click="currentPage++" :disabled="currentPage >= totalPages">下一页</button> </div> </template> <script> import { ref, computed } from 'vue'; // 模拟大量数据 const items = ref(Array.from({ length: 100 }, (_, i) => ({ id: i + 1, name: `项目 ${i + 1}` }))); const pageSize = 10; // 每页显示 10 条 const currentPage = ref(1); // 当前页码 // 计算当前页数据 const currentPageItems = computed(() => { const start = (currentPage.value - 1) * pageSize; const end = start + pageSize; return items.value.slice(start, end); }); // 计算总页数 const totalPages = computed(() => { return Math.ceil(items.value.length / pageSize); }); </script>

三、总结

  1. 条件渲染

    • v-if 完全移除 / 创建元素,v-show 仅隐藏 / 显示元素,根据场景选择;
    • 避免 v-if 和 v-for 同时使用,优先用计算属性过滤数据;
    • 多元素条件渲染用 <template> 包裹,减少额外 DOM 节点。
  2. 循环渲染

    • 始终为 v-for 项添加唯一 key,优先使用数据的唯一标识;
    • 熟悉响应式数组方法,直接修改索引不会触发更新;
    • 大型列表需分页或虚拟滚动优化性能;
    • 用计算属性处理过滤、排序等逻辑,提高代码可读性。

好了好了,Vue 条件与循环渲染分享到此结束!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值