vue2.x学习笔记(八)
接着前面的内容:https://www.cnblogs.com/yanggb/p/12577433.html。
列表渲染
vue提供了一个【v-for】指令用于列表渲染(循环)。
用【v-for】指令把一个数组对应为一组元素
我们可以使用【v-for】指令基于一个数组来渲染一个列表。使用【v-for】指令需要使用【item in items】形式的特殊语法,其中items是源数据数组,而item则是被迭代的数组元素的别名。
<ul id="example-1"> <li v-for="item in items"> {{ item.message }} </li> </ul>
var example1 = new Vue({ el: '#example-1', data: { items: [ { message: 'Foo' }, { message: 'Bar' } ] } })
在【v-for】块中,我们可以访问所有父作用域的属性。此外,【v-for】指令还支持一个可选的第二参数,为当前项的索引。
<ul id="example-2"> <li v-for="(item, index) in items"> {{ parentMessage }} - {{ index }} - {{ item.message }} </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>
是不是像极了javascript中的【for-of】语法?
在【v-for】指令中使用对象
除了遍历数组之外,【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: { title: 'How to do lists in Vue', author: 'Jane Doe', publishedAt: '2016-04-10' } } })
同样的,你也可以提供第二个参数作为property的名称(key键名)。
<div v-for="(value, name) in object"> {{ name }}: {{ value }} </div>
更多的,还可以使用第三个参数作为索引。
<div v-for="(value, name, index) in object"> {{ index }}. {{ name }}: {{ value }} </div>
注意到遍历数组和遍历对象的差别了吗?这里有个差别就是遍历对象是支持三个参数的,分别是键值、键名和索引,而遍历数组则只支持两个参数,分别是元素和索引。
另外要注意的是,在遍历对象的时候,会按照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】指令的时候提供key属性,除非遍历输出的dom内容非常简单,或者是刻意依赖默认行为以获得性能上的提升。
因为key是vue识别节点的一个通用机制,并不是仅仅与【v-for】指令有特别关联。事实上,其还有一些别的用途,在之后的学习中会再次得到更多的了解。
此外,官方文档特别标注了,不要使用对象或数组之类的非基本类型值作为【v-for】指令的key,请用字符串或数值类型的值,否则可能导致意外的问题。
在【v-for】指令中的使用值范围
【v-for】指令也可以接受整数,在这种情况下,它会把模板重复对应次数。
<div> <span v-for="n in 10">{{ n }} </span> </div>
其实就是一个固定次数的循环。
在<template>上使用【v-for】指令
类似于【v-if】,你也可以利用带有【v-for】指令的<template>来循环渲染一段包含多个元素的内容,相当于循环分组。
<ul> <template v-for="item in items"> <li>{{ item.msg }}</li> <li class="divider" role="presentation"></li> </template> </ul>
因为<template>是vue模板的语法,所以并不会被渲染到最终的输出结果中。
【v-for】指令和【v-if】指令一同使用
当【v-if】指令与【v-for】指令一起使用的时候,【v-for】指令会拥有比【v-if】更高的优先级,这样的机制意味着,【v-if】指令将分别重复运行于每个【v-for】指令循环中。当你只想为部分项渲染节点的时候,这种优先级的机制会十分有用。
<li v-for="todo in todos" v-if="!todo.isComplete"> {{ todo }} </li>
以上的代码将只会渲染出未完成的todo。
但是如果你的目的是有条件地跳过循环的执行,则需要将【v-if】指令置于外层元素(或者<template>)上。
<ul v-if="todos.length"> <li v-for="todo in todos"> {{ todo }} </li> </ul> <p v-else>No todos left!</p>
总结就是,将【v-if】和【v-for】指令放在同一个元素中,相当于在循环中写if,而将【v-if】提在【v-for】指令外层,则相当于在if中写循环。
在组件使用【v-for】指令
在自定义的组件上,可以像任何普通元素一样使用【v-for】指令。
<my-component v-for="item in items" :key="item.id"></my-component>
在2.2.0+的版本,当在组件上使用【v-for】指令的时候,key是必须的,目的是使每个组件实例能独立被渲染。
在上面的例子中,并没有自动传递任何数据到组件中,这是因为组件拥有着自己的独立作用域。为了能够把迭代的数据传递到组件中,我们必须使用prop手动将数据传到组件中。
<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】指令的运作紧密耦合,不符合组件设计的初衷。明确组件数据的来源能够保证组件是一个独立的整体,从而使得组件能够在其他场合重复使用。
来看一个简单的todo列表的完整例子:
<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>
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 = '' } } })
注意这里的【is="todo-item"】属性,这样的写法和【<todo-item></todo-item>】的写法效果是一样的,但是可以避开一些潜在的浏览器解析错误。因为在<ul>元素里只有<li>元素会被看作有效内容,这样的写法就相当于给组件套模板,将组件里定义的<li>元素套到页面的<li>元素上。简单的理解就是规范组件的套用从而避免浏览器解析组件出错,因此这种写法在使用dom模板的时候是十分必要的。
"我还是很喜欢你,像仲夏流萤四起,弦月沉西。"