条件渲染
条件指令:v-if、v-else-if、v-else
因为必须添加到一个元素上。如果想切换多个元素(分组),可以把一个<template>元素当做不可见的包裹元素,并在上面使用v-if。最终的渲染结果将不包含<template>元素。
注意:v-else/v-else-if必须紧跟在带v-if或v-else-if的元素之后。
用key管理可复用的元素
Vue会尽可能高效地渲染元素。
如:两个模版使用了相同的元素,元素不会被替换,只是替换了元素的属性值。
要想这两个元素是完全独立的,不要复用它们。只需添加一个具有唯一值的key属性即可。
v-show指令:用于根据条件展示元素的选项。
【注意】不同之处是:
(1)带有v-show的元素始终会被渲染并保留在DOM中。v-show只是简单地切换元素的CSS属性display。
(2)v-show不支持<template>元素,也不支持v-else。
【比较】v-if 和 v-show
v-if是真正的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if也是惰性的:如果在初始渲染时条件为假,则什么也不做,直到条件第一次变为真时,才会开始渲染条件块。
相比之下,v-show不管初始条件是什么,元素总是会被渲染,并且只是简单地基于CSS进行切换。
一般来说,v-if有更高的切换开销,而v-show有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用v-show较好;如果在运行时条件很少改变,则使用v-if较好。
v-if 与 v-for 一起使用
当v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级。
列表渲染
用 v-for 把一个数组对应为一组元素
- { { item.message }}
var vm = new Vue({ el: '#example-1', data: { items: [ { message: 'Foo' }, { message: 'Bar' } ] }})
在 v-for 块中,拥有对父作用域属性的完全访问权限。
v-for 还支持一个可选的第二个参数为当前项的索引。
- { { parentMessage }} - { { index }} - { { item.message }}
var vm = new Vue({ el: '#example-2', data: { parentMessage: 'Parent', items: [ { message: 'Foo' }, { message: 'Bar' } ] }})
也可以用 of 替代 in 作为分隔符,因为它是最接近JavaScript迭代器的语法。
一个对象的 v-for
也可以用 v-for 通过一个对象的属性来迭代。
- { { value }}
new Vue({ el: '#v-for-object', data: { object: { firstName: 'John', lastName: 'Doe', age: 30 } }})
也可以提供第二个参数为键名:
{ { key }}: { { value }}
第三个参数为索引:
{ { index }}. { { key }}: { { value }}
【注意】
在遍历对象时,是按 Object.keys() 的结果遍历,但是不能保证它的结果在不同的JavaScript引擎下是一致的。
key
用 v-for 更新已渲染过的元素列表时,默认用“就地复用”策略。如果数据项的顺序被改变,Vue将不会移动DOM元素来匹配数据项的顺序,而是简单复用此处每个元素,并且确保它在特定索引下显示已被渲染过的每个元素。
建议尽可能在使用 v-for 时提供 key ,除非遍历输出的DOM内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。
数组更新检测
# 变异方法
Vue包含一组观察数组的变异方法,所以它们也将会触发视图更新。
push()、pop()、shift()、unshift()、splice()、sort()、reverse()
# 替换数组
变异方法,会改变被这些方法调用的原始数组。
非变异方法,不会改变原始数组,但总是返回一个新数组。当使用非变异方法时,可以用新数组替换旧数组。
filter()、concat()、slice()
Vue为了使得DOM元素得到最大范围的重用而实现了一些智能的、启发式的方法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。
# 注意事项
由于JavaScript的限制,Vue不能检测以下变动的数组:
(1)当你利用索引直接设置一个项时,例如:vm.items[indexOfItems] = newValue
(2)当你修改数组的长度时,例如:vm.items.length = newLength
为了解决第一类问题,以下两种方式都可以实现和vm.items[indexOfItems] = newValue相同的效果,同时也将触发状态更新:
// Vue.setVue.set(vm.items, indexOfItem, newValue) 或vm.$set(vm.items, indexOfItem, newValue)
vm.$set实例方法使全局方法Vue.set的一个别名
// Array.prototype.splicevm.items.splice(indexOfItem, 1, newValue)
为了解决第二类问题,可以使用splice:
vm.items.splice(newLength)
对象更改检测注意事项
由于JavaScript的限制,Vue不能检测对象属性的添加或删除。
var vm = new Vue({ data: { a: 1 }})// `vm.a` 现在是响应式的vm.b = 2// `vm.b` 不是响应式的
对于已经创建的实例,Vue不能动态添加根级别的响应式属性。但是,可以使用Vue.set(object, key, value)方法向嵌套对象添加响应式属性。
var vm = new Vue({ data: { userProfile: { name: 'Anika' } }})
添加一个新的 age
属性到嵌套的 userProfile
对象:
Vue.set(vm.userProfile, 'age', 27)
或
vm.$set(vm.userProfile, 'age', 27)
为已有对象赋予多个新属性,比如使用Object.assign() 或 _.extend()时,应该用两个对象的属性创建一个新的对象。
例如:给vm.userProfile追加两个新属性
Object.assign(vm.userProfile, { age: 27, favoriteColor: 'Vue Green'})
上面分方法不是响应式的属性,应该如下操作:
vm.userProfile = Object.assign({}, vm.userProfile, { age: 27, favoriteColor: 'Vue Green'})
显示过滤/排序结果
有时想要显示一个数组的过滤或排序副本,而不实际改变或重置原始数据。可以创建返回过滤或排序数组的计算属性。
data: { numbers: [ 1, 2, 3, 4, 5 ]},computed: { evenNumbers: function () { return this.numbers.filter(function (number) { return number % 2 === 0 }) }}
在计算属性不适用的情况下(例如,在嵌套v-for循环中)可以使用一个method方法:
data: { numbers: [ 1, 2, 3, 4, 5 ]},methods: { even: function (numbers) { return numbers.filter(function (number) { return number % 2 === 0 }) }}
一段取值范围的v-for
v-for也可以取整数。在这种情况下,它将重复多次模版。
{ { n }}
结果:12345678910
v-for on a <template>
类似与 v-if ,可以利用带有 v-for 的<template> 渲染多个元素。
v-for with v-if
当它们处于同一个节点,v-for 的优先级比 v-if 更高,即 v-if 将分别重复运行于每个 v-for 循环中。
上面的代码只传递了未完成的 todos。
有条件地跳过循环的执行,可以将 v-if 置于外层元素 (或<template>)上。如:
- { { todo }}
No todos left!
一个组件的 v-for
在自定义组件里,可以像任何普通元素一样使用v-for。
在2.2.0+的版本里,当在组件中使用 v-for 时,key现在是必须的。
任何数据都不会被自动传递到组件里,因为组件有自己独立的作用域。为了把迭代数据传递到组件里,要用props:
其中,item、index作为属性传递到组件中。
不自动将item注入到组件里的原因是,避免使得组件与 v-for 的运作紧密耦合。
明确组件数据的来源能够使组件在其它场合重复使用。
完整实例:
【注意】
这里的 is="todo-item"
属性。这种做法在使用 DOM 模板时是十分必要的,因为在 <ul>
元素内只有 <li>
元素会被看作有效内容。这样做实现的效果与 <todo-item>
相同,但是可以避开一些潜在的浏览器解析错误。查看 来了解更多信息。
Vue.component('todo-item', { template: '\