VueJS 列表渲染

  • v-for 遍历数组

    我们可以使用 v-for 指令基于数组呈现项目列表。
    v-for 指令需要在 item 中使用 item 形式的特殊语法,其中 item 是源数据数组,而 item 是要在其上迭代的数组元素的别名:
    <ul id="example-1">
       <li v-for="item in items">
          {{ item.message }}
       </li>
    </ul>
    <script>
       var example1 = new Vue({
          el: '#example-1',
          data: {
             items: [
                { message: 'Foo' },
                { message: 'Bar' }
             ]
          }
       });
    </script>
    
    尝试一下
    v-for 块中,我们可以完全访问父范围属性。v-for 还为当前项目的索引支持可选的第二个参数。
    <ul id="example-2">
       <li v-for="(item, index) in items">
          {{ parentMessage }} - {{ index }} - {{ item.message }}
       </li>
    </ul>
    <script>
       var example2 = new Vue({
          el: '#example-2',
          data: {
             parentMessage: 'Parent',
             items: [
                { message: 'Foo' },
                { message: 'Bar' }
             ]
          }
       });
    </script>
    
    尝试一下
    您还可以将 of 用作分隔符,而不是 in,以使其更接近 JavaScript 的迭代器语法:
    <div v-for="item of items"></div>
  • v-for 遍历对象

    您也可以使用 v-for 遍历对象的属性。
    <ul id="v-for-object" class="demo">
       <li v-for="value in object">
          {{ value }}
       </li>
    </ul>
    <script>
       new Vue({
          el: '#v-for-object',
          data: {
             object: {
                title: '如何在Vue中执行清单',
                author: '菜鸟教程',
                publishedAt: '2019-11-19'
             }
          }
       });
    </script>
    
    尝试一下
    您还可以为属性名称(也称为键)提供第二个参数,而另一个作为索引值:
    <ul id="v-for-object2" class="demo">
       <li v-for="(value, name, index) in object">
          {{ index }}. {{ name }}: {{ value }}
       </li>
    </ul>
    <script>
       new Vue({
          el: '#v-for-object2',
          data: {
             object: {
                title: '如何在Vue中执行清单',
                author: '菜鸟教程',
                publishedAt: '2019-11-19'
             }
          }
       });
    </script>
    
    尝试一下
    在对象上进行迭代时,该顺序基于 Object.keys() 的枚举顺序,这不能保证在 JavaScript 引擎实现之间是一致的。
  • 维持状态

    Vue 更新用 v-for 渲染的元素列表时,默认情况下,它使用“就地补丁”策略。 如果数据项的顺序已更改,则 Vue 不会移动 DOM 元素以使其与项的顺序匹配,而是会在适当位置修补每个元素,并确保其反映应在该特定索引处呈现的内容。 这类似于 Vue1.xtrack-by = "$index" 的行为。
    此默认模式是有效的,但是仅当列表呈现输出不依赖于子组件状态或临时 DOM 状态(例如,表单输入值)时才适用。
    为了给 Vue 一个提示,使其可以跟踪每个节点的身份,从而重用和重新排列现有元素,您需要为每个项目提供唯一的 key 属性:
    <div v-for="item in items" v-bind:key="item.id">
       // 内容
    </div>
    
    建议尽可能在 v-for 中提供键属性,除非迭代的 DOM 内容很简单,或者您故意依赖默认行为来提高性能。
    由于这是 Vue 识别节点的通用机制,因此该键还具有其他用途,这些用途并不专门与 v-for 绑定,我们将在本指南的后面部分看到。
    请勿将对象和数组之类的非原始值用作v-for键。 请改用字符串或数字值。
  • 数组的变异方法

    Vue 封装了观察到的数组的变异方法,因此它们也将触发视图更新。包装的方法是:
    • push()
    • pop()
    • shift()
    • unshift()
    • splice()
    • sort()
    • reverse()
    您可以打开控制台,并通过调用它们的变异方法来处理前面的示例的 items 数组。 例如:example1.items.push({message:'Baz'})。
    顾名思义,变异方法会变异调用它们的原始数组。 相比之下,也有非变异方法,例如 filter()concat()slice() 不会改变原始数组,但总是返回一个新数组。 使用非变异方法时,可以将旧数组替换为新数组:
    example1.items = example1.items.filter(function (item) {
       return item.message.match(/Foo/)
    });
    
    您可能会认为这将导致 Vue 丢弃现有 DOM 并重新呈现整个列表-幸运的是,事实并非如此。 Vue 实现了一些智能试探法,以最大化 DOM 元素的重用,因此,用另一个包含重叠对象的数组替换一个数组是非常有效的操作。
  • 显示筛选/排序结果

    有时,我们希望显示过滤后或排序后的数组版本,而无需实际更改或重置原始数据。在这种情况下,您可以创建一个计算属性,该属性返回过滤或排序的数组。
    <ul id="app">
       <li v-for="n in evenNumbers">
          {{ n }}
       </li>
    </ul>
    <script>
       new Vue({
          el: '#app',
          data: {
             numbers: [ 1, 2, 3, 4, 5 ]
          },
          computed: {
             evenNumbers: function () {
               return this.numbers.filter(function (number) {
                 return number % 2 === 0
               })
             }
          }
       });
    </script>
    
    尝试一下
    在计算属性不可行的情况下(例如在嵌套的v-for循环内),可以使用以下方法:
    <ul id="app">
       <li v-for="n in even(numbers)">
          {{ n }}
       </li>
    </ul>
    <script>
       new Vue({
          el: '#app',
          data: {
             numbers: [ 1, 2, 3, 4, 5 ]
          },
          methods: {
             even: function (numbers) {
               return numbers.filter(function (number) {
                 return number % 2 === 0
               })
             }
          }
       });
    </script>
    
    尝试一下
  • v-for 与组件

    您可以像任何普通元素一样直接在自定义组件上使用 v-for
    <my-component v-for="item in items" :key="item.id"></my-component>  
    
    在2.2.0+中,当对组件使用v-for时,现在需要一个key。
    但是,这不会自动将任何数据传递给组件,因为组件具有各自独立的作用域。 为了将迭代的数据传递到组件中,我们还应该使用 props
    <my-component
       v-for="(item, index) in items"
       v-bind:item="item"
       v-bind:index="index"
       v-bind:key="item.id"
    ></my-component>
    
    不自动将项目注入组件的原因是,这使组件与v-for的工作原理紧密耦合。 明确说明其数据来自何处使得该组件可在其他情况下重用。
    下面演示了一个简单的 TodoList 的完整示例:
    <div id="todo-list-example">
       <form v-on:submit.prevent="addNewTodo">
          <label for="new-todo">添加你的选项</label>
          <input
             v-model="newTodoText"
             id="new-todo"
             placeholder="请输入内容"
          >
          <button>添加</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>
    <script>
       Vue.component('todo-item', {
          template: '\
             <li>\
                {{ title }}\
                <button v-on:click="$emit(\'remove\')">删除</button>\
              </li>\
          ',
          props: ['title']
       })
    
       new Vue({
          el: '#todo-list-example',
          data: {
             newTodoText: '',
             todos: [
                {
                id: 1,
                title: 'HTML5',
                },
                {
                id: 2,
                title: 'CSS3',
                },
                {
                id: 3,
                title: 'VueJS'
                }
             ],
             nextTodoId: 4
          },
          methods: {
             addNewTodo: function () {
                this.todos.push({
                   id: this.nextTodoId++,
                   title: this.newTodoText
                })
                this.newTodoText = ''
             }
          }
       });
    </script>
    
    尝试一下
    注意 is=“todo-item” 属性。 这在 DOM 模板中是必需的,因为在 <ul> 中只有 <li> 元素有效。 它的作用与 <todo-item> 相同,但是可以解决潜在的浏览器解析错误