在实际开发中,我们经常需要根据条件显示或隐藏某些内容,或者渲染一个列表。Vue提供了强大的指令来处理这些场景:v-if、v-show用于条件渲染,v-for用于列表渲染。掌握这些指令,你就能构建出更加动态和灵活的界面。
这节课让我们将深入学习这些指令的用法,了解它们之间的区别,以及如何在实际项目中正确使用它们。这些知识是构建复杂应用的基础。

v-if指令用于根据特定条件来决定一个元素是否被渲染。当你在元素上添加v-if="条件"时,Vue会首先计算这个条件表达式。如果这个表达式的值为真(truthy),那么该元素及其子元素会被插入到DOM中;
如果条件为假(falsy),则该元素和其子元素根本不会出现在页面的DOM结构里。这意味着,v-if不仅仅是简单的隐藏元素,而是直接从DOM树中添加或移除元素,从而提升性能并确保页面上只显示符合条件的内容。
让我们从一个简单的例子开始:
|<div id="app"> <p v-if="isVisible">这段文字只有在isVisible为true时才会显示</p> </div> <script> const { createApp, ref } = Vue; const app = createApp({ setup() { const isVisible = ref(true); return { isVisible }; } }); app.mount('#app'); </script>
在这个例子中,<p>元素只有在isVisible为true时才会被渲染。如果isVisible为false,这个元素根本不会出现在DOM中。
我们可以通过修改isVisible的值来控制元素的显示和隐藏:
|<div id="app"> <p v-if="isVisible">这段文字只有在isVisible为true时才会显示</p> <button @click="toggle">切换显示</button> </div> <script> const { createApp, ref } = Vue; const app = createApp
当我们点击"切换显示"按钮时,isVisible的值会在true和false之间切换,<p>元素会相应地出现或消失。
v-if的表达式可以是任何JavaScript表达式,不仅仅是简单的布尔值:
|<div id="app"> <p v-if="count > 0">计数大于0</p> <p v-if="user && user.name">用户名:{{ user.name }}</p> <p v-if="items.length > 0">有 {{ items.length }} 个项目</p> </div> <script> const { createApp, ref
在这个例子中,我们使用了比较表达式、逻辑与表达式和属性访问表达式。Vue会计算这些表达式的值,根据结果决定是否渲染元素。
在开发过程中,除了通过v-if判断条件来决定是否渲染某个元素外,我们还经常需要在条件不成立时渲染不同的内容。为此,Vue 提供了与 v-if 配合使用的 v-else 和 v-else-if 指令。
v-else:用于指定在前面的 v-if 或 v-else-if 条件为 false 时要显示的内容。v-else 不能单独使用,必须紧跟在 v-if 或 v-else-if 的元素后面,并且它本身不需要写任何表达式。v-else-if:用于添加额外的条件判断,功能类似于 JavaScript 里的 else if。它同样需要紧挨着前一个 v-if 或 v-else-if 元素,且需要写一个条件表达式。通过组合 v-if、v-else-if 和 v-else,我们可以根据不同的条件渲染不同的内容,使页面交互更加灵活:
|<div id="app"> <p v-if="isLoggedIn">欢迎回来!</p> <p v-else>请先登录</p> </div> <script> const { createApp, ref } = Vue; const app = createApp({ setup
在这个例子中,如果isLoggedIn为true,显示"欢迎回来!";否则显示"请先登录"。
v-else-if用于实现多个条件的判断,类似于JavaScript中的else if:
|<div id="app"> <p v-if="score >= 90">优秀</p> <p v-else-if="score >= 80">良好</p> <p v-else-if="score >= 60">及格</p> <p v-else>不及格</p> </div> <script>
这个例子根据分数显示不同的等级。Vue会从上到下检查条件,第一个满足条件的元素会被渲染,后续的v-else-if和v-else会被忽略。
v-else和v-else-if必须紧跟在v-if或v-else-if元素之后,中间不能有其他元素。如果它们之间有其他元素,Vue无法正确识别它们的关系。
v-show是Vue中用于条件渲染的另一个指令。它的基本用法与v-if类似,都可以根据表达式的真假来控制元素的显示和隐藏:
|<div id="app"> <p v-show="isVisible">这段文字会通过CSS的display属性控制显示</p> <button @click="toggle">切换显示</button> </div> <script> const { createApp, ref } = Vue; const app = createApp
理解v-if和v-show的区别很重要,这会影响应用的性能和用户体验。
v-if是"真正的"条件渲染,因为它会确保在切换过程中,条件块内的事件监听器和子组件被适当地销毁和重建。v-if也是惰性的:如果在初始渲染时条件为假,则什么也不做,直到条件第一次变为真时才会开始渲染条件块。
相比之下,v-show就简单得多:不管初始条件是什么,元素总是会被渲染,并且只是简单地基于CSS进行切换。
一般来说,v-if有更高的切换开销,而v-show有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用v-show较好;如果在运行时条件很少改变,则使用v-if较好。
让我们通过一个例子来理解这个区别:
|<div id="app"> <div> <h3>使用v-if(切换开销高)</h3> <button @click="showIf = !showIf">切换v-if</button> <div v-if="showIf"> <p>这是v-if的内容</p> <input type="text" placeholder="输入内容">
在这个例子中,使用v-if时,当条件为false时,<div>及其内部的<input>元素都不会存在于DOM中。当条件变为true时,这些元素才会被创建。使用v-show时,<div>始终存在于DOM中,只是通过CSS的display属性控制显示。
如果元素需要频繁切换显示和隐藏,使用v-show性能更好。如果元素很少改变,或者需要条件性地创建和销毁组件,使用v-if更合适。
v-for指令是Vue中用于遍历和渲染列表内容的核心语法。通过v-for,我们可以根据一个数组或对象的数据结构,重复渲染元素或组件。每一次遍历,都会为当前项生成一个新的DOM节点或模板块。
例如,如果你有一个存储水果名称的数组,使用v-for可以让每一个水果都渲染成页面上的一个列表项。v-for的基本语法为:v-for="item in items",其中items是要遍历的数据源,item是每次循环时的当前元素。
同时,你还可以通过第二个参数获取当前循环的索引,例如:v-for="(item, index) in items"。这种用法常用于需要显示序号或调试数据时:
|<div id="app"> <ul> <li v-for="item in items">{{ item }}</li> </ul> </div> <script> const { createApp, ref } = Vue; const app = createApp({
在这个例子中,v-for="item in items"会遍历items数组,为每个元素创建一个<li>。item是当前遍历到的数组元素,可以在模板中使用。
我们也可以获取数组的索引:
|<div id="app"> <ul> <li v-for="(item, index) in items"> {{ index + 1 }}. {{ item }} </li> </ul> </div> <script> const { createApp, ref } = Vue; const app =
在这个例子中,我们使用(item, index)来同时获取元素和索引。注意,索引是第二个参数,第一个参数是元素本身。
在使用v-for时,Vue建议为每个元素提供一个唯一的key属性。key帮助Vue识别每个节点,从而重用和重新排序现有元素。
让我们先看看不使用key的情况:
|<div id="app"> <ul> <li v-for="item in items"> <input type="checkbox"> {{ item }} </li> </ul> <button @click="addItem">添加项目</button> </div> <
如果你在这个例子中勾选某个复选框,然后点击"添加项目"按钮,你可能会发现复选框的状态会错乱。这是因为Vue在更新DOM时,会尽可能地复用已有的元素,如果没有key,Vue无法正确识别哪个元素对应哪个数据。
现在让我们添加key属性,来帮助Vue正确识别每个元素:
|<div id="app"> <ul> <li v-for="(item, index) in items" :key="index"> <input type="checkbox"> {{ item }} </li> </ul> <button @click="addItem">添加项目</button> </div
我们使用:key="index"来为每个元素提供key。但是,使用索引作为key并不是最佳实践,因为当数组顺序改变时,索引也会改变,可能导致问题。
更好的做法是使用每个元素的唯一标识符,比如使用每个元素的id:
|<div id="app"> <ul> <li v-for="item in items" :key="item.id"> <input type="checkbox"> {{ item.name }} </li> </ul> <button @click="addItem">添加项目</button> </div
在这个例子中,我们使用item.id作为key,这是每个元素的唯一标识符。这样,即使数组顺序改变,Vue也能正确识别每个元素。
使用v-for时,应该始终提供key属性,并且key应该是唯一的、稳定的标识符。不要使用索引作为key,除非列表是静态的且不会重新排序。
v-for指令不仅限于遍历数组结构,还支持对对象(Object)的属性进行迭代。通过这种方式,我们可以直接遍历一个对象的每一个键值对,对象中的每个属性(key)及其对应的值(value)都能够被访问和渲染。
这种用法在处理结构化用户数据、参数映射等需求时非常实用。例如,如果你有一个包含多个字段的用户信息对象,可以通过v-for高效渲染每一项属性及其对应的值。具体写法如下:
|<div id="app"> <ul> <li v-for="(value, key) in user"> {{ key }}: {{ value }} </li> </ul> </div> <script> const { createApp, ref } = Vue; const app =
在这个例子中,v-for="(value, key) in user"会遍历user对象的所有属性。value是属性的值,key是属性的名称。我们还可以获取索引:
|<div id="app"> <ul> <li v-for="(value, key, index) in user"> {{ index + 1 }}. {{ key }}: {{ value }} </li> </ul> </div>
注意,遍历对象时,参数的顺序是(value, key, index),而不是(key, value, index)。
除了遍历数组或对象,v-for还支持遍历一个数字范围,从1开始递增,直到指定的最大值。例如,v-for="n in 10" 会让模板块渲染10次,每次n的值依次为1、2、3……直到10。你可以用它快速生成重复的结构,比如数字列表、占位符等。
|<div id="app"> <span v-for="n in 10">{{ n }} </span> </div> <script> const { createApp } = Vue; const app = createApp({}); app.mount('#app'); </script
这个例子会显示数字1到10。v-for="n in 10"会从1开始遍历到10(包括10)。
有时候,我们需要在v-for循环时为每一项生成多个相邻的元素。例如,有时候你需要为每个数据项渲染多个标签(比如标题和内容),但这些标签本身不能被一个共同的父元素包裹。如果你直接这么写,HTML结构可能不合法,或者会导致你只能渲染其中一个元素。此时,可以使用Vue的<template>标签。
<template>标签是一个“虚拟包裹元素”,它本身不会被渲染到最终的DOM中,但允许你在其内部放置多个元素,然后通过v-for对它们一并处理。这样你可以为每一项数据生成一组结构化的内容,而不用担心多出来的多余父元素。
|<div id="app"> <template v-for="item in items" :key="item.id"> <h3>{{ item.title }}</h3> <p>{{ item.content }}</p> <hr> </template> </div> <script> const { createApp
当v-for和v-if同时用在同一个元素节点上时,Vue 的编译顺序是先处理v-if,再处理v-for。也就是说,v-if在v-for执行之前就会被判断,此时还无法获得v-for循环中每一项生成的局部变量。
这会导致你在v-if表达式里访问v-for当前项的数据时,实际上这些变量是未定义的。因此,在实际开发中,不建议将v-for和v-if同时用在同一个节点上,否则会出现变量作用域错误或无法按预期渲染的问题。
|<!-- 这样不会工作 --> <li v-for="item in items" v-if="item.visible"> {{ item.name }} </li>
正确的做法是将v-if移到<template>标签上,或者使用计算属性过滤列表:
|<div id="app"> <ul> <template v-for="item in items" :key="item.id"> <li v-if="item.visible"> {{ item.name }} </li> </template> </ul> </div> <script>
或者使用计算属性:
|<div id="app"> <ul> <li v-for="item in visibleItems" :key="item.id"> {{ item.name }} </li> </ul> </div> <script> const { createApp, ref, computed } = Vue;
使用计算属性是更好的做法,因为它将过滤逻辑从模板中分离出来,代码更清晰,性能也更好。
为了帮助大家更好地理解所学内容,我们来做一个详细的综合示例。这个例子将手把手带你实现一个常见的“待办事项列表”功能,同时结合条件渲染 (v-if/v-else) 和列表渲染 (v-for) 的用法。
通过这个例子,你将看到如何根据数据动态显示不同的内容,以及如何高效地渲染和操作一个列表,让代码结构更加清晰易懂。
|<div id="app"> <h2>待办事项</h2> <input v-model="newTodo" @keyup.enter="addTodo" placeholder="输入待办事项"> <div v-if="todos.length === 0" class="empty"> 暂无待办事项 </div> <ul v-else
在这个例子中,我们使用了多种条件渲染和列表渲染的技巧。当没有待办事项时,显示"暂无待办事项";否则显示待办列表。我们使用v-for遍历待办事项,使用v-if控制统计信息的显示。每个待办事项都有唯一的id作为key。
|<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>待办事项列表</title> <script src="https://unpkg.com/vue@3/dist/vue.global.js"></
在这节课中,我们学习了条件渲染和列表渲染。v-if、v-else、v-else-if用于条件渲染,v-show用于切换显示,v-for用于列表渲染。我们还学习了key属性的重要性,以及如何正确使用这些指令。
这些指令是构建动态界面的基础。掌握它们后,你就能创建出根据数据动态变化的用户界面。
在下一个部分,我们会深入学习事件处理,了解事件修饰符、按键修饰符等高级特性,这些知识对于构建更加交互性强的应用至关重要。