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.x 中 track-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> 相同,但是可以解决潜在的浏览器解析错误