v-for指令
1、遍历数组
v-for指令将根据接收到的数组中的数据重复渲染DOM元素。该指令需要使用item in items形式的语法,其中,items为数据对象中的数组名称,item为数组元素的别名,通过别名可以获取当前数组遍历的每个元素。
例如,应用v-for指令将
- 标签循环渲染,输出数组中存储的职位名称。代码如下:
html
<div id="app">
<ul>
<li v-for="item in items">{{item.position}}</li>
</ul>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const vm = Vue.createApp({
data() {
return {
items: [
{position: '前端工程师'},
{position: '一二线运维'},
{position: '项目经理'}
]
}
},
}).mount('#app');//装载应用实例的根组件
</script>

在应用v-for指令遍历数组时,还可以指定一个参数作为当前数组元素的索引,语法格式为(item,index) initems。其中,items为数组名称,item为数组元素的别名,index为数组元素的索引。
例如,应用v-for指令将<li>标签循环渲染,输出数组中存 储的职位名称和相应的索引。代码如下:
html
<div id="app">
<ul>
<li v-for="(item, index) in items">{{index}}-{{item.position}}</li>
</ul>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const vm = Vue.createApp({
data() {
return {
items: [
{position: '前端工程师'},
{position: '一二线运维'},
{position: '项目经理'}
]
}
},
}).mount('#app');//装载应用实例的根组件
</script>

示例:输出商品信息。
应用v-for指令输出商品列表中的商品名称、商品类型以及商品价格,代码如下:
html
<div id="app">
<div class="title">
<div class="col-1">序号</div>
<div class="col-1">商品名称</div>
<div class="col-1">商品类型</div>
<div class="col-2">商品价格</div>
</div>
<div class="content" v-for="(goods, index) in goodslist">
<div class="col-1">{{index + 1}}</div>
<div class="col-1">{{goods.name}}</div>
<div class="col-1">{{goods.type}}</div>
<div class="col-2">{{goods.price}}</div>
</div>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const vm = Vue.createApp({
data() {
return {
goodslist: [
{name: '64GU盘', type: '外部设备', price: 39.9},
{name: '榨汁机', type: '家用电器', price: 169},
{name: '数码相机', type: '摄影摄像', price: 369},
]
}
},
}).mount('#app');//装载应用实例的根组件
</script>

1.2、循环一组元素
与v-if指令类似,如果需要对一组元素进行循环,可以使用<template>元素作为包装元素,并在该元素上使用v-for。
html
<div id="app">
<ul>
<template v-for="menu in munulist">
<li class="item">{{menu}}</li>
</template>
</ul>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const vm = Vue.createApp({
data() {
return {
munulist: ['首页', '课程', '读书', '社区', '服务中心']
}
},
}).mount('#app');//装载应用实例的根组件
</script>

1.3、更新数组
Vue.js中包含了一些检测数组变化的变异方法,调用这些方法可以改变原始数组,并触发视图更新。这些变异方法的说明如表所示。
| 方法 | 说明 |
|---|---|
push() |
向数组的末尾添加一个或多个元素 |
pop() |
将数组中的最后一个元素从数组中删除 |
shift() |
将数组中的第一个元素从数组中删除 |
unshift() |
向数组的开头添加一个或多个元素 |
splice() |
添加或删除数组中的元素 |
sort() |
对数组的元素进行排序 |
reverse() |
颠倒数组中元素的顺序 |
例如,应用变异方法push()向数组中添加一个元素,并应用v-for指令将<li>标签循环渲染,输出数组中存储的职位名称。代码如下:
html
<div id="app">
<ul>
<li v-for="item in items">{{item.position}}</li>
</ul>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const vm = Vue.createApp({
data() {
return {
items: [
{position: '前端工程师'},
{position: '一二线运维'},
{position: '项目经理'},
]
}
},
}).mount('#app');//装载应用实例的根组件
vm.items.push({position: '系统管理员'});
</script>

示例:2022年手机销量排行榜。
将2022年手机销量排行榜前五名的手机品牌和销售市场份额定义在数组中,对数组按手机销售市场份额进行降序排序,将排序后的手机品牌排名、手机品牌和市场份额输出在页面中。代码如下:
html
<div id="app">
<div class="content" v-for="(phone, index) in phonelist">
<div class="col-1">{{index + 1}}</div>
<div class="col-2">{{phone.brand}}</div>
<div class="col-1">{{phone.share}}</div>
</div>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const vm = Vue.createApp({
data() {
return {
phonelist: [
{brand: 'OPPP', share: 17.5},
{brand: '小米', share: 13.9},
{brand: '荣耀', share: 16.7},
{brand: 'iPhone', share: 18.0},
]
}
},
}).mount('#app');//装载应用实例的根组件
vm.phonelist.sort((a, b) => {
return a.brand < b.brand ? 1 : -1;
})
</script>

除了变异方法,Vue.js还包含了几个非变异方法,如filter()、concat()和slice()方法。调用这些方法不会改变原始数组,而是返回一个新的数组。当使用非变异方法时,可以用新的数组替换原来的数组。
例如,应用slice()方法获取数组中第一个元素后的所有元素,代码如下:
html
<div id="app">
<ul>
<li v-for="item in items">{{item.position}}</li>
</ul>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const vm = Vue.createApp({
data() {
return {
items: [
{position: '前端工程师'},
{position: '一二线运维'},
{position: '项目经理'},
]
}
},
}).mount('#app');//装载应用实例的根组件
vm.items = vm.items.slice(1);
</script>

由于JavaScript的限制,Vue.js不能检测到通过修改数组长度引起的变化,如vm.items.length=2。为了解决这个问题,可以使用splice()方法修改数组的长度。例如,将数组的长度修改为2,代码如下:
html
<div id="app">
<ul>
<li v-for="item in items">{{item.position}}</li>
</ul>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const vm = Vue.createApp({
data() {
return {
items: [
{position: '前端工程师'},
{position: '一二线运维'},
{position: '项目经理'},
]
}
},
}).mount('#app');//装载应用实例的根组件
vm.items.splice(2);
</script>

2、遍历对象
2.1、基本用法
应用v-for指令除了可以遍历数组,还可以遍历对象。遍历对象使用value in object形式的语法,其中,object为对象名称,value为对象属性值的别名。
例如,应用v-for指令将<li>标签循环渲染,输出对象中存储的员工信息。代码如下:
html
<div id="app">
<ul>
<li v-for="value in employee">{{value}}</li>
</ul>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const vm = Vue.createApp({
data() {
return {
employee: {
name: '张三',
position: '前端工程师',
year: 10
}
}
},
}).mount('#app');//装载应用实例的根组件
</script>

在应用v-for指令遍历对象时,还可以使用第二个参数为对象属性名(键名)提供一个别名,语法格式为(value,key) in object。其中,object为对象名称,value为对象属性值的别名,key为对象属性名的别名。
例如,应用v-for指令输出对象中的属性名和属性值。代码如下:
html
<div id="app">
<ul>
<li v-for="(value, key) in employee">{{key}}:{{value}}</li>
</ul>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const vm = Vue.createApp({
data() {
return {
employee: {
name: '张三',
position: '前端工程师',
year: 10
}
}
},
}).mount('#app');//装载应用实例的根组件
</script>

在应用v-for指令遍历对象时,还可以使用第三个参数为对象提供索引,语法格式为(value,key,index)inobject。其中,object为对象名称,value为对象属性值的别名,key为对象属性名的别名,index为对象的索引。
例如,应用v-for指令输出对象中的属性和相应的索引。
html
<div id="app">
<ul>
<li v-for="(value, key, index) in employee">{{index}}-{{key}}:{{value}}</li>
</ul>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const vm = Vue.createApp({
data() {
return {
employee: {
name: '张三',
position: '前端工程师',
year: 10
}
}
},
}).mount('#app');//装载应用实例的根组件
</script>

2.2、向对象中添加响应式属性
如果需要向对象中添加一个或多个响应式属性,可以使用Object.assign()方法。在使用该方法时,需要将源对象的属性和新添加的属性合并为一个新的对象。
例如,应用Object.assign()方法向对象中添加两个新的属性。代码如下:
html
<div id="app">
<ul>
<li v-for="(value, key, index) in employee">{{index}}-{{key}}:{{value}}</li>
</ul>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const vm = Vue.createApp({
data() {
return {
employee: {
name: '张三',
position: '前端工程师',
year: 10
}
}
},
}).mount('#app');
vm.employee = Object.assign({}, vm.employee, {
department: '开发部',
entrytime: '2023年3月30日'
});
</script>

3、遍历整数
v-for指令也可以遍历整数,接收的整数即为循环次数,根据循环次数将模板重复整数次。
例如,某单位正式员工的工作年限每增加一年,工龄工资就增长500元,输出一个工作5年的员工每一年的工龄工资增加情况,代码如下:
html
<div id="app">
<div v-for="n in 5">员工第{{n}}年工龄工资为{{n *salary}}元</div>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const vm = Vue.createApp({
data() {
return {
salary: 500,
}
},
}).mount('#app');
</script>

示例:输出九九乘法表。
html
<div id="app">
<div v-for="n in 9">
<span v-for="m in n">
{{m}} * {{n}}={{m*n}}
</span>
</div>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const vm = Vue.createApp({
data() {
return {
}
},
}).mount('#app');
</script>

4、key属性
使用v-for指令渲染的元素列表在更新时,如果数据项的顺序被改变,Vue不会移动DOM元素来匹配数据项的顺序,而是就地更新每个元素。为了使Vue能跟踪每个DOM元素,需要为每一个数据项提供一个唯一的key属性。
下面是一个不使用key属性的示例,代码如下:
html
<div id="app">
<div>请输入职位:<input type="text" size="15" v-model="pos">
<button v-on:click="add()">添加职位</button>
</div>
<p v-for="item in items">
<input type="checkbox">
<span>{{item.position}}</span>
</p>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script type="text/javascript">
const vm = Vue.createApp({
data() {
return {
pos: '',
items: [
{position: '前端工程师'},
{position: '一二线工程师'},
{position: '项目经理'},
]
}
},
methods: {
add: function() {
this.items.unshift({
position:this.pos
})
}
}
}).mount('#app');
</script>


在输入框中输入新的职位,单击"添加职位"按钮后,向职位数组开头添加了一个新职位,结果如图所示。
由结果可以看出,选择的选项变成了新添加的职位,产生问题的原因是v-for指令的"就地更新"策略。当向数组中添加内容时,指令只记住了刚开始选择的数组下标0,于是就选择了新数组中下标为0的选项。为了解决这个问题,需要在v-for指令的后面添加key属性。代码如下:
html
<div id="app">
<div>请输入职位:<input type="text" size="15" v-model="pos">
<button v-on:click="add()">添加职位</button>
</div>
<p v-for="item in items" v-bind:key="item.position">
<input type="checkbox">
<span>{{item.position}}</span>
</p>
</div>
