v-for

  • 该指令基于一个数组来渲染一个列表

  • 该指令的值需要使用item in items形式的特殊语法

  • 其中items是源数据的数组,而item是迭代项的别名

data() {
  return {
    items: [{ message: 'Foo' }, { message: 'Bar' }]
  }
}

<li v-for="item in items">
  {{ item.message }}
</li>
  • 在v-for块中可以完整地访问父作用域内的属性和变量

  • v-for也支持使用可选的第二个参数表示当前项的位置索引

data() {
  return {
    parentMessage: 'Parent',
    items: [{ message: 'Foo' }, { message: 'Bar' }]
  }
}

<li v-for="(item, index) in items">
  {{ parentMessage }} - {{ index }} - {{ item.message }}
</li>
  • v-for变量的作用域和JavaScript代码很类似

const parentMessage = 'Parent'
const items = [
  /* ... */
]

items.forEach((item, index) => {
  // 可以访问外层的 `parentMessage`
  // 而 `item` 和 `index` 只在这个作用域可用
  console.log(parentMessage, item.message, index)
})
  • 可以在定义v-for的变量别名时使用解构,和解构函数类似

<li v-for="{ message } in items">
  {{ message }}
</li>

<!-- 有 index 索引时 -->
<li v-for="({ message }, index) in items">
  {{ message }} {{ index }}
</li>


//多层嵌套的v-for,作用域的工作方式和函数的作用域很类似
//每个v-for作用域都可以访问到父级作用域
<li v-for="item in items">
  <span v-for="childItem in item.children">
    {{ item.message }} {{ childItem }}
  </span>
</li>

//也可以使用of作为分隔符来代替in,这更接近JavaScript的迭代器语法
<div v-for="item of items"></div>

v-for与对象

可以使用v-for来遍历一个对象的所有属性,遍历的顺序会基于该对象调用object.keys()的返回值来决定。

data() {
  return {
    myObject: {
      title: 'How to do lists in Vue',
      author: 'Jane Doe',
      publishedAt: '2016-04-10'
    }
  }
}

<ul>
  <li v-for="value in myObject">
    {{ value }}
  </li>
</ul>

//通过第二个参数表示属性名
<li v-for="(value, key) in myObject">
  {{ key }}: {{ value }}
</li>

//第三个参数表示位置索引
<li v-for="(value, key, index) in myObject">
  {{ index }}. {{ key }}: {{ value }}
</li>

在v-for里面使用范围值

v-for可以直接接受一个整数值,会将该模板基于1……n的取值范围重复多次。

<span v-for="n in 10">{{ n }}</span>
//注意此处的n的初始值从1开始而非0

<template>上的v-for

与模板上的v-if类似,可以在<template>标签上使用v-for来渲染一个包含多个元素的块。

<ul>
  <template v-for="item in items">
    <li>{{ item.msg }}</li>
    <li class="divider" role="presentation"></li>
  </template>
</ul>

v-for和v-if

  • 同时存在于一个节点上时,v-if比v-for的优先级更高,这将导致v-if的条件将无法访问到v-for作用域内定义的变量别名

<!--
 这会抛出一个错误,因为属性 todo 此时
 没有在该实例上定义
-->
<li v-for="todo in todos" v-if="!todo.isComplete">
  {{ todo.name }}
</li>

//解决方法:
<template v-for="todo in todos">
  <li v-if="!todo.isComplete">
    {{ todo.name }}
  </li>
</template>

通过key管理状态

  • 默认按照就地更新的策略更新通过v-for渲染的元素列表

  • 数据项的顺序改变时,Vue不会随之移动DOM元素的顺序,而是就地更新每个元素,确保在其原本指定的索引位置上渲染

  • 默认模式只适用于列表渲染输出的结果不依赖子组件状态或者临时DOM状态(例如表单输入值)的情况

  • 便于Vue跟踪每个节点的标识,需要为每个元素对应的块提供一个唯一的key attribute

<div v-for="item in items" :key="item.id">
  <!-- 内容 -->
</div>

//当使用<template v-for>时,key应该被放置在这个<template>容器上
<template v-for="todo in todos" :key="todo.name">
  <li>{{ todo.name }}</li>
</template>

Tips:

  • 不要和在v-for中使用对象里所提到的对象属性名混淆

  • 推荐在任何可行的时候为v-for提供一个key attribute(除非DOM内容非常简单或者有意采用默认模式提高性能)

  • key绑定的值期望是一个基础类型的值,例如字符串或者number类型,不要用对象类型

组件上使用v-for

【标记】学完组件知识后再学习该小结

数组变化侦测

变更方法

Vue侦听响应式数组的变更方法,在它们被调用时触发相关的更新,即对调用它们的原数组进行变更。

  • push()

  • pop()

  • shift()

  • unshift()

  • splice()

  • sort()

  • reverse()

替换一个数组

不可变方法(immutable),例如filter()、concat()、slice(),它们都不会更改原数组,而总是返回一个新数组。

this.items = this.items.filter((item) => item.message.match(/Foo/))
//该方法并不会导致Vue丢弃现有的DOM并重新渲染整个列表

展示过滤或排序后的结果

有时需要显示数组经过过滤或者排序后的内容,而不实际变更或重置原始数据,此时可以创建返回已过滤或已排序数组的计算属性。

data() {
  return {
    numbers: [1, 2, 3, 4, 5]
  }
},
computed: {
  evenNumbers() {
    return this.numbers.filter(n => n % 2 === 0)
  }
}

<li v-for="n in evenNumbers">{{ n }}</li>

在计算属性不可行的情况,如多层嵌套的v-for循环中。

data() {
  return {
    sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]]
  }
},
methods: {
  even(numbers) {
    return numbers.filter(number => number % 2 === 0)
  }
}

<ul v-for="numbers in sets">
  <li v-for="n in even(numbers)">{{ n }}</li>
</ul>

在计算属性中使用reverse()和sort()时需要注意,这两个方法将变更原始数组,计算函数不应该使用,而是在调用这些方法之前创建一个原数组的副本

- return numbers.reverse()
+ return [...numbers].reverse()

文章作者: Sleny
版权声明: 本站所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 咸鱼说
Vue Vue
喜欢就支持一下吧
打赏
微信 微信
支付宝 支付宝