指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 true
时才被渲染。例如在一个简单的用户登录状态判断场景中:
<div id="app">
<p v-if="isLoggedIn">欢迎回来,用户!p>
<p v-if="!isLoggedIn">请先登录。p>
div>
<script>
const vm = new Vue({
el: '#app',
data: {
isLoggedIn: false
}
});
script>
还可以结合计算属性使用 v-if
,以处理更复杂的条件逻辑。比如判断用户是否是高级会员且积分大于 1000:
<div id="app">
<p v-if="isEligibleForReward">您有资格获得奖励!p>
div>
<script>
const vm = new Vue({
el: '#app',
data: {
isPremiumMember: false,
points: 800
},
computed: {
isEligibleForReward() {
return this.isPremiumMember && this.points > 1000;
}
}
});
script>
顾名思义,v-else-if
提供的是相应于 v-if
的“else if 区块”。它可以连续多次重复使用。
一个使用 v-else-if
的元素必须紧跟在一个 v-if
或一个 v-else-if
元素后面。
你也可以使用 v-else
为 v-if
添加一个“else 区块”,当然,v-else
元素也是必须紧跟在一个 v-if
或一个 v-else-if
元素后面。
需求:根据温度判断天气情况
温度:<input type="number" v-model="temprature" ><br /><br />
天气:<span v-if="temprature <= 10">寒冷span>
<span v-else-if="temprature <= 25">凉爽span>
<span v-else>炎热span>
<hr>
还可以增加更多的判断区间,如:
温度:<input type="number" v-model="temprature" ><br /><br />
天气:<span v-if="temprature <= 0">极寒span>
<span v-else-if="temprature <= 10">寒冷span>
<span v-else-if="temprature <= 25">凉爽span>
<span v-else-if="temprature <= 35">炎热span>
<span v-else>酷热span>
<hr>
同时,可以结合函数来处理条件判断,使代码更具可读性和可维护性:
温度:<input type="number" v-model="temprature" ><br /><br />
天气:<span v-if="getWeatherCondition(temprature) === '极寒'">极寒span>
<span v-else-if="getWeatherCondition(temprature) === '寒冷'">寒冷span>
<span v-else-if="getWeatherCondition(temprature) === '凉爽'">凉爽span>
<span v-else-if="getWeatherCondition(temprature) === '炎热'">炎热span>
<span v-else>酷热span>
<hr>
<script>
const vm = new Vue({
el: '#app',
data: {
temprature: 20
},
methods: {
getWeatherCondition(temp) {
if (temp <= 0) return '极寒';
if (temp <= 10) return '寒冷';
if (temp <= 25) return '凉爽';
if (temp <= 35) return '炎热';
return '酷热';
}
}
});
script>
与 v-if因为 v-if
是一个指令,它必须依附于某个元素。
但如果我们想要切换不止一个元素呢?
在这种情况下我们可以在一个 元素上使用
v-if
,
这只是一个不可见的包装器元素,最后渲染的结果并不会包含这个 元素。
v-else
和 v-else-if
也可以在 上使用。
<template v-if="counter === 10">
<h2>六下匹,人当送,内。h2>
<h3>六下匹,人当送,内。h3>
<h4>六下匹,人当送,内。h4>
template>
可以结合动态数据,让其更具实用性,比如:
<template v-if="userRole === 'admin'">
<button @click="manageUsers">管理用户button>
<button @click="managePosts">管理文章button>
template>
<template v-else-if="userRole === 'editor'">
<button @click="editPosts">编辑文章button>
template>
<template v-else>
<p>您没有特殊权限。p>
template>
另一个可以用来按条件显示一个元素的指令是 v-show
。其用法基本一样:
<div v-show="false">v-show-{{msg}}div>
<div v-show="2 === 1">v-show-{{msg}}div>
不同之处在于 v-show
会在 DOM 渲染中保留该元素;v-show
仅切换了该元素上名为 display
的 CSS 属性。
不能和 v-else
搭配使用。可以结合动态数据进行演示:
<div id="app">
<button @click="toggleShow">切换显示button>
<div v-show="isShown">这是一个用 v-show 控制显示的元素。div>
div>
<script>
const vm = new Vue({
el: '#app',
data: {
isShown: true
},
methods: {
toggleShow() {
this.isShown = !this.isShown;
}
}
});
script>
可以添加多个元素使用 v-show
进行控制,并且结合 CSS 过渡效果,让显示和隐藏更平滑:
<style>
.fade {
transition: opacity 0.5s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
style>
<div id="app">
<button @click="toggleShow1">切换显示1button>
<button @click="toggleShow2">切换显示2button>
<div v-show="isShown1" class="fade">这是第一个用 v-show 控制显示的元素。div>
<div v-show="isShown2" class="fade">这是第二个用 v-show 控制显示的元素。div>
div>
<script>
const vm = new Vue({
el: '#app',
data: {
isShown1: true,
isShown2: false
},
methods: {
toggleShow1() {
this.isShown1 = !this.isShown1;
},
toggleShow2() {
this.isShown2 = !this.isShown2;
}
}
});
script>
v-if
是“真实的”按条件渲染,因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建
v-if
也是惰性的:如果在初次渲染时条件值为 false
,则不会做任何事。条件区块只有当条件首次变为 true
时才被渲染。相比之下,v-show
简单许多,元素无论初始条件如何,始终会被渲染,只有 CSS display
属性会被切换。
总的来说,v-if
有更高的切换开销,而 v-show
有更高的初始渲染开销。因此,如果需要频繁切换,则使用 v-show
较好;如果在运行时绑定条件很少改变,则 v-if
会更合适。
可以通过一个示例来更直观地感受:
<div id="app">
<button @click="toggleCondition">切换条件button>
<div v-if="useIf">使用 v-if 渲染的元素div>
<div v-show="useShow">使用 v-show 渲染的元素div>
div>
<script>
const vm = new Vue({
el: '#app',
data: {
useIf: false,
useShow: false
},
methods: {
toggleCondition() {
this.useIf = !this.useIf;
this.useShow = !this.useShow;
}
}
});
script>
还可以在控制台打印一些信息,来观察 v-if
和 v-show
在切换时的不同表现:
<div id="app">
<button @click="toggleCondition">切换条件button>
<div v-if="useIf" @mounted="onIfMounted" @destroyed="onIfDestroyed">使用 v-if 渲染的元素div>
<div v-show="useShow">使用 v-show 渲染的元素div>
div>
<script>
const vm = new Vue({
el: '#app',
data: {
useIf: false,
useShow: false
},
methods: {
toggleCondition() {
this.useIf = !this.useIf;
this.useShow = !this.useShow;
},
onIfMounted() {
console.log('v-if 元素挂载');
},
onIfDestroyed() {
console.log('v-if 元素销毁');
}
}
});
script>
语法格式:v-for
指令。该指令用在被遍历的标签上。
v-for="(element, index) in elements" :key="element.id"
或者
v-for="(element, index) of elements" :key="element.id"
1、遍历对象
<h2>遍历对象的属性h2>
<ul>
<li v-for="(value, propertyName) of user">{{propertyName}},{{value}}li>
ul>
<hr />
可以添加更多的对象属性进行遍历,并且可以对对象进行动态修改:
<div id="app">
<h2>遍历对象的属性h2>
<ul>
<li v-for="(value, propertyName) of user">{{propertyName}},{{value}}li>
ul>
<button @click="addProperty">添加属性button>
<button @click="removeProperty">删除属性button>
div>
<script>
const vm = new Vue({
el: '#app',
data: {
user: {
name: '张三',
age: 20,
gender: '男'
}
},
methods: {
addProperty() {
this.user.email = '[email protected]';
},
removeProperty() {
delete this.user.age;
}
}
});
script>
2、遍历字符串
<h2>遍历字符串h2>
<ul>
<li v-for="(c,index) of str">{{index}},{{c}}li>
ul>
<hr />
可以添加一个输入框,让用户输入字符串进行遍历,并且可以对字符串进行反转操作:
<div id="app">
<h2>遍历字符串h2>
<input type="text" v-model="str">
<button @click="reverseString">反转字符串button>
<ul>
<li v-for="(c,index) of str">{{index}},{{c}}li>
ul>
div>
<script>
const vm = new Vue({
el: '#app',
data: {
str: 'Hello'
},
methods: {
reverseString() {
this.str = this.str.split('').reverse().join('');
}
}
});
script>
3、遍历指定次数
<h2>遍历指定的次数h2>
<ul>
<li v-for="(num,index) of counter">{{index}}, {{num}}li>
ul>
<hr />
可以添加一个输入框,让用户指定遍历的次数,并且可以根据输入的次数生成一个数字数组:
<div id="app">
<h2>遍历指定的次数h2>
<input type="number" v-model="counter">
<button @click="generateArray">生成数组button>
<ul>
<li v-for="(num,index) of numberArray">{{index}}, {{num}}li>
ul>
div>
<script>
const vm = new Vue({
el: '#app',
data: {
counter: 5,
numberArray: []
},
methods: {
generateArray() {
this.numberArray = Array.from({ length: this.counter }, (_, i) => i + 1);
}
}
});
script>
4、遍历数组
<h2>遍历数组h2>
<ul>
<li>张三li>
<li>李四li>
<li>王五li>
ul>
<ul>
<li v-for="(name,index) of names">{{name}}-{{index}}li>
ul>
<table>
<tr>
<th>序号th>
<th>会员名th>
<th>年龄th>
<th>选择th>
tr>
<tr v-for="(vip,index) in vips">
<td>{{index+1}}td>
<td>{{vip.name}}td>
<td>{{vip.age}}td>
<td><input type="checkbox" />td>
tr>
table>
可以添加一些操作按钮,对数组进行增删改操作,并且可以对数组进行排序:
<div id="app">
<h2>遍历数组h2>
<ul>
<li v-for="(name,index) of names">{{name}}-{{index}} <button @click="removeName(index)">删除button>li>
ul>
<input type="text" v-model="newName">
<button @click="addName">添加button>
<button @click="sortNames">排序button>
<table>
<tr>
<th>序号th>
<th>会员名th>
<th>年龄th>
<th>选择th>
tr>
<tr v-for="(vip,index) in vips">
<td>{{index+1}}td>
<td>{{vip.name}}td>
<td>{{vip.age}}td>
<td><input type="checkbox" />td>
tr>
table>
div>
<script>
const vm = new Vue({
el: '#app',
data: {
names: ['张三', '李四', '王五'],
newName: '',
vips: [
{ name: '会员1', age: 20 },
{ name: '会员2', age: 25 },
{ name: '会员3', age: 30 }
]
},
methods: {
removeName(index) {
this.names.splice(index, 1);
},
addName() {
if (this.newName) {
this.names.push(this.newName);
this.newName = '';
}
},
sortNames() {
this.names.sort();
}
}
});
script>
虚拟DOM:在内存中的dom对象。Vue 通过虚拟 DOM 来提升渲染效率,避免直接操作真实 DOM 带来的性能开销。虚拟 DOM 是一种轻量级的 JavaScript 对象,它是真实 DOM 的抽象表示。Vue 在数据发生变化时,会先在虚拟 DOM 层面进行计算和比较,找出最小的 DOM 更新范围,然后再将这些变化应用到真实 DOM 上。
diff算法:是一种能够快速地比较出两个事物不同之处的算法。在 Vue 中,diff 算法用于比较新旧虚拟 DOM 树的差异,从而确定需要对真实 DOM 进行哪些更新操作。
v-for
指令所在的标签中,还有一个非常重要的属性::key
。如果没有指定 :key
属性,会自动拿 index
作为 key
。这个 key
是这个 dom
元素的身份证号/唯一标识。
1、 虚拟DOM中 key
的作用(diff到底是怎么做对比?):
key
是虚拟DOM中对象的标识,当数据发生变化时,Vue会根据新数据生成新的虚拟DOM,随后Vue进行新虚拟DOM与旧虚拟DOM的差异比较,比较规则如下:
key
:
key
快速识别到这一项,直接复用之前的真实 DOM 节点,而不需要重新创建和渲染。key
:则直接创建新的真实DOM,随后渲染到页面。当有新的数据项添加到列表中时,Vue 会为其创建新的真实 DOM 节点并插入到合适的位置。2、 用 index
作为 key
可能会引发的问题
index
作为 key
时,当列表顺序改变,每个元素的 index
都会发生变化,Vue 会认为每个元素都是新的,从而进行不必要的 DOM 操作,降低了渲染效率。例如,在列表头部插入一个新元素,后面所有元素的 index
都会加 1,Vue 会重新渲染所有元素。input
、checked
等表单元素。当使用 index
作为 key
且列表顺序改变时,表单元素的值可能会与错误的数据项关联。例如,原来第一个输入框的值可能会显示在第二个输入框中。3、开发中如何选择 key
key
,比如 id
、手机号、身份证号、学号等唯一值。这样可以确保每个数据项都有一个稳定的 key
,无论数据的顺序如何变化,Vue 都能准确地识别每个数据项,避免不必要的 DOM 操作和界面错乱问题。index
的情况:如果不存在对数据的逆序添加,逆序删除等破坏顺序的操作,仅用于渲染列表,使用 index
作为 key
是没有问题的。例如,一个静态的列表展示,数据不会发生变化,使用 index
作为 key
可以简化代码。DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>虚拟dom与diff算法title>
<script src="../js/vue.js">script>
<style>
th,
td {
border: 1px solid black;
}
style>
head>
<body>
<div id="app">
<h1>{{msg}}h1>
<table>
<tr>
<th>序号th>
<th>英雄th>
<th>能量值th>
<th>选择th>
tr>
<tr v-for="(hero,index) in heros" :key="index">
<td>{{index+1}}td>
<td>{{hero.name}}td>
<td>{{hero.power}}td>
<td><input type="checkbox" />td>
tr>
table>
<table>
<tr>
<th>序号th>
<th>英雄th>
<th>能量值th>
<th>选择th>
tr>
<tr v-for="hero in heros" :key="hero.id">
<td>{{heros.indexOf(hero)+1}}td>
<td>{{hero.name}}td>
<td>{{hero.power}}td>
<td><input type="checkbox" />td>
tr>
table>
<button @click="addAtStart">在开头添加英雄麦文button>
<button @click="addAtEnd">在末尾添加英雄麦文button>
div>
<script>
const vm = new Vue({
el: "#app",
data: {
msg: "虚拟dom与diff算法",
heros: [
{ id: "101", name: "艾格文", power: 10000 },
{ id: "102", name: "麦迪文", power: 9000 },
{ id: "103", name: "古尔丹", power: 8000 },
{ id: "104", name: "萨尔", power: 6000 },
],
},
methods: {
addAtStart() {
this.heros.unshift({ id: "105", name: "麦文", power: 9100 });
},
addAtEnd() {
this.heros.push({ id: "105", name: "麦文", power: 9100 });
},
},
});
script>
body>
html>