数组监测案例
点击修改,页面未变化,查看控制台打印信息(
items
是最新数据):- 加上
this.$forceUpdate()
,页面更新。 -
也可以直接用vm.$set()或给items重新赋值或用数组方法,如下:
- 再来看个神奇的操作【这里应该涉及到
diff
算法、VNODE
,另行学习】
将修改按钮的函数改成如上图,这时候点击修改按钮
this.items[1] = {message:'See'}
这句也一起起效了哦!
数组(或对象)更新检测
直接调用数组方法触发更新
Vue
将被侦听的数组的变异方法进行了包裹,所以它们也将会触发视图更新。这些被包裹过的方法包括:push()
、pop()
、shift()
、unshift()
、splice()
、sort()
、reverse()
。如上述案例中调用:
this.items.pop() //删除最后一个元素
this.items.push({message:'See'})//新增一个元素
点击修改按钮,执行上述代码,页面即可更新。
替换数组(数组重新赋值)
上述案例可以直接用如下代码,页面即可更新:
this.items= [
{ message: 'Foo' },
{ message: 'See' }
]
数组中有些方法执行后,原数组不会发生变化, 如filter()
、concat()
和 slice()
。它们不会改变原始数组,而总是返回一个新数组。当调用这些方法(非变异方法)时,可以用新数组替换旧数组
this.items = this.items.filter(function (item) {
return item.message.match(/Foo/)
})
你可能认为这将导致 Vue
丢弃现有 DOM
并重新渲染整个列表。幸运的是,事实并非如此。Vue
为了使得 DOM
元素得到最大范围的重用而实现了一些智能的启发式方法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。
数组更新的注意事项
由于 JavaScript
的限制,Vue 不能检测以下数组的变动(可以参看文首案例):
- 当你利用索引直接设置一个数组项时,例如:
vm.items[indexOfItem] = newValue
- 当你修改数组的长度时,例如:
vm.items.length = newLength
(可以用splice
) - 好好看下第一个案例,各种使它生效的方法
对象变更检测注意事项
- 点击修改按钮,页面没有变化(
upt
方法加一句this.user.sex='女'
页面会变化,两个属性改变都生效,和数组一个意思) - 还是由于
JavaScript
的限制,Vue
不能检测对象属性的添加或删除:
var vm = new Vue({
data: {
a: 1
}
})
// `vm.a` 现在是响应式的
vm.b = 2
// `vm.b` 不是响应式的
- 对于已经创建的实例,
Vue
不允许动态添加根级别的响应式属性。但是,可以使用Vue.set(object, propertyName, value)
(vm.$set
) 方法向嵌套对象添加响应式属性 - 有时你可能需要为已有对象赋值多个新属性,比如使用
Object.assign()
或_.extend()
。在这种情况下,你应该用两个对象的属性创建一个新的对象。所以,如果你想添加新的响应式属性,不要像这样:
Object.assign(vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
你应该这样做:
vm.userProfile = Object.assign({}, vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
列表渲染v-for
- 新版本
key
不要少 -
index
:当前项的索引 - 可以用
of
替代in
作为分隔符
<div v-for="item of items"></div>
- 你也可以用
v-for
来遍历一个对象的属性
<!--
object: {
title: 'How to do lists in Vue',
author: 'Jane Doe',
publishedAt: '2016-04-10'
}
-->
<ul id="v-for-object" class="demo">
<li v-for="value in object">
{{ value }}
</li>
</ul>
<!--
value:键值, name:键名 , index:索引
<div v-for="(value, name, index) in object" :key="index">name</div>
-->
-
显示过滤/排序后的结果
有时,我们想要显示一个数组经过过滤或排序后的版本,而不实际改变或重置原始数据。在这种情况下,可以创建一个计算属性,来返回过滤或排序后的数组。
在计算属性不适用的情况下 (例如,在嵌套 v-for 循环中) 你可以使用一个方法:
计算属性和侦听器
计算属性缓存 vs 方法
我们可以将同一函数定义为一个方法而不是一个计算属性。
两种方式的最终结果确实是完全相同的。
然而,不同的是计算属性是基于它们的响应式依赖进行缓存的。
只在相关响应式依赖发生改变时它们才会重新求值。
这就意味着只要 message 还没有发生改变,
多次访问 reversedMessage 计算属性会立即返回之前的计算结果,
而不必再次执行函数。
这也同样意味着下面的计算属性将不再更新,
因为 Date.now() 不是响应式依赖:
computed: {
now: function () {
return Date.now()
}
}
相比之下,每当触发重新渲染时,
调用方法将总会再次执行函数。
我们为什么需要缓存?
假设我们有一个性能开销比较大的计算属性 A,它需要遍历一个巨大的数组并做大量的计算。
然后我们可能有其他的计算属性依赖于 A 。
如果没有缓存,我们将不可避免的多次执行 A 的 getter!
如果你不希望有缓存,请用方法来替代。
计算属性 vs 侦听属性
Vue 提供了一种更通用的方式来观察和响应 Vue 实例上的数据变动:侦听属性。
当你有一些数据需要随着其它数据变动而变动时,你很容易滥用 watch——
特别是如果你之前使用过 AngularJS。
然而,通常更好的做法是使用计算属性而不是命令式的 watch 回调。
-
v-for
也可以接受整数
<span v-for="n in 10">{{ n }} </span>
- 不推荐在同一元素上使用
v-if
和v-for
<!--
当它们处于同一节点,`v-for` 的优先级比 `v-if` 更高,
这意味着 `v-if` 将分别重复运行于每个 `v-for` 循环中。
而如果你的目的是有条件地跳过循环的执行,
那么可以将 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-for
v-for
维护状态(v-for
循环中key
有什么作用)
- 当
Vue
正在更新使用v-for
渲染的元素列表时,它默认使用“就地更新”的策略。如果数据项的顺序被改变,Vue
将不会移动DOM
元素来匹配数据项的顺序,而是就地更新每个元素,并且确保它们在每个索引位置正确渲染 - 这个默认的模式是高效的,但是只适用于不依赖子组件状态或临时
DOM
状态 (例如:表单输入值) 的列表渲染输出。 - 为了给
Vue
一个提示,以便它能跟踪每个节点的身份,从而重用和重新排序现有元素,你需要为每项提供一个唯一key
属性:
<div v-for="item in items" v-bind:key="item.id">
<!-- 内容 -->
</div>
- 建议尽可能在使用
v-for
时提供key attribute
,除非遍历输出的DOM
内容非常简单,或者是刻意依赖默认行为以获取性能上的提升。 - 因为它是
Vue
识别节点的一个通用机制,key
并不仅与v-for
特别关联。后面我们将在指南中看到,它还具有其它用途。 - 不要使用对象或数组之类的非基本类型值作为
v-for
的key
。请用字符串或数值类型的值。 - 更多
key attribute
的细节用法请移步至 key 的 API 文档。 -
key
的特殊属性主要用在Vue
的虚拟DOM
算法,在新旧nodes
对比时辨识VNodes
。 - 如果不使用
key
,Vue
会使用一种最大限度减少动态元素并且尽可能的尝试修复/再利用相同类型元素的算法。使用key
,它会基于key
的变化重新排列元素顺序,并且会移除key
不存在的元素。