列表渲染

286 阅读2分钟

原文: https://cn.vuejs.org/v2/guide/list.html#v-for-with-v-if

用v-for把一个数组对应为一组元素


` v-for `指令需要会用`item in items`形式的特殊语法,`items`是元数据数组并且`item`是数组元素迭代的别名。
在`v-for`块中,我们拥有对父作用域属性的完全访问权限。`v-for`还支持一个可选的第二个参数为当前项的索引。

<ul id="example-2">
    <li v-for="(item, index) in items">
    </li>
</ul>


var example2 = new Vue({
    el: '#example-2',
    data: {
        parentMessage: 'Parent',
        items:[
            { message: 'Foo' },
            { message: 'Bar' }
        ]
    }
})

也可以用of代替in作为分隔符,因为它是最接近JavaScript迭代器的语法:

<div v-for="item of items"> </div>

对象的属性迭代 v-for

  • 提供一个参数为迭代的别名
<ul id="v-for-object" class="demo">
  <li v-for="value in object">
    {{ value }}
  </li>
</ul>


new Vue({
  el: '#v-for-object',
  data: {
    object: {
      firstName: 'John',
      lastName: 'Doe',
      age: 30
    }
  }
})

  • 提供第二个的参数为键名
    <div v-for="(value, key) in object"></div>
  • 提供第三个参数为索引
    <div v-for="(value, key, index) in object">
    {{ index }}. {{ key }}: {{ value }}
    </div>

提示: 在遍历对象时,是按object.keys()的结果遍历,但是不能保证 它的结果在不同的JavaScript引擎下是一致的

key

当vue.js正在更新已渲染过的元素列表时,它默认用就地复用策略。如果数据项的顺序被改变,Vue将不会移动DOM来匹配数据项的顺序,而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。这个类似Vue 1.x的track-by="$index"
这个默认的模式是高效的,但是只适用于不依赖组价状态或临时DOM状态(例如:表单输入值)的列表渲染输出
为了给Vue一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,因而需要没每项提供一个唯一key属性。理想的key值是每项都有的唯一id。 这个特殊的属性相当于Vue 1.x的track-by,但它的工作方式类似于一个属性,所以需要用v-bind来绑定动态值:

<div v-for="item in items" :key="item.id">

建议尽可能在使用v-for 时提供key ,除非遍历输出的DOM内容非常简单,或者是可以依赖默认行为以获取性能上的提升。
因为它是Vue识别节点的一个通用机制,key并不与v-for特别关联,key还具有其他用途


不要使用对象或数组之类的给原始类型值作为v-forkey。用字符串或数类型的值取而代之。


数组更新检测

变异方法

vue包含一组观察数组的变异方法,所以他们也将会触发视图更新。

  • push()
  • pop()
  • shift()
  • unshift()
  • splice()
  • sort()
  • reverse()

替换数组

变异方法,会改变被这些方法调用的原始狐族。相比之下,也有非变异方法,例如:filter(),concat()slice()。这些不会改变原始数组,但总是返回一个新的数组。当使用非变异方法时,可以用心数组替换旧数组


example.items = example.items.filter(function (item){
    return item.message.match(/Foo/)
})

注意事项

由于JavaScript的限制,vue不能检测以下变动的数组: 1. 利用索引值直接设置一个项时,例如:vm.items[indexOfItem] = newValue 2. 修改数组的长度时,例如: vm.items.length = newLength

v-forwithv-if


当它们处于同一节点,v-for的优先级比v-if更高,这意味着v-if将分别运行于每个v-for循环中。

一个组件的v-for


2.2.0+的版本里,当在组件中使用v-for 时,key现在是必须的


<my-component
  v-for="(item, index) in items"
  v-bind:item="item"
  v-bind:index="index"
  v-bind:key="item.id">
  </my-component>

不自动将 item 注入到组件里的原因是,这会使得组件与 v-for 的运作紧密耦合。明确组件数据的来源能够使组件在其他场合重复使用。


下面是一个简单的TODOlist的完整例子
    <div id="todo-list-example">
    <form v-on:submit.prevent="addNewTodo">
        <label for="new-todo">Add a todo</label>
        <input
        v-model="newTodoText"
        id="new-todo"
        placeholder="E.g. Feed the cat"
        >
        <button>Add</button>
    </form>
    <ul>
        <li
        is="todo-item"
        v-for="(todo, index) in todos"
        v-bind:key="todo.id"
        v-bind:title="todo.title"
        v-on:remove="todos.splice(index, 1)"
        ></li>
    </ul>
    </div>

注意这里的is="todo-item" 属性。这种做法在使用 DOM 模板时是十分必要的,因为在<ul>元素内只有 <li>元素会被看作有效内容。这样做实现的效果与 <todo-item> 相同,但是可以避开一些潜在的浏览器解析错误。查看 DOM 模板解析说明 来了解更多信息。


Vue.component('todo-item', {
  template: '\
    <li>\
      {{ title }}\
      <button v-on:click="$emit(\'remove\')">Remove</button>\
    </li>\
  ',
  props: ['title']
})

new Vue({
  el: '#todo-list-example',
  data: {
    newTodoText: '',
    todos: [
      {
        id: 1,
        title: 'Do the dishes',
      },
      {
        id: 2,
        title: 'Take out the trash',
      },
      {
        id: 3,
        title: 'Mow the lawn'
      }
    ],
    nextTodoId: 4
  },
  methods: {
    addNewTodo: function () {
      this.todos.push({
        id: this.nextTodoId++,
        title: this.newTodoText
      })
      this.newTodoText = ''
    }
  }
})