检测变化
vue是数据驱动的视图框架DOM是通过数据映射的,只有数据改变,DOM才改变
那么数据是怎么来的呢?
1.来自父元素的属性(prop)
2.来自组件的自身状态(data)
3.来自状态管理器,如Vuex,Vue.observable
那么状态(data)和属性(prop)他们发生改变数据就一定发生更新吗?答案是什么呢?是否定的
1.data函数中的return对象中未声明我们改变的值
2.data函数中的return对象中声明了,当html结构上没使用
3.由于 JavaScript 的限制,Vue 不能检测以下变动的数组:
- 当你利用索引直接设置一个项时,例如:
vm.items[indexOfItem] = newValue
- 当你修改数组的长度时,例如:
vm.items.length = newLength
那为什么会这样呢?
当vue实例化的时候(render:生成虚拟DOM的过程)会对Data里的数据进行转化,就是对数据进行代理层,不管是拿数据(getter),还是改数据(setter),当我们的数据用到了(在html中或template)我们才会放到数据放到watcher中,上面第一点:没在data中不可以(Vue 会警告你渲染函数正在试图访问的属性不存在),上面的第二点只有被(template和html)用到了发生了改变(setter)才会更新,当我们的数据没有被(template和html)用到的时候不会将数据绑定到Watcher上,所以不会触发更新,第三是为什么呢?
变异方法
我们先来说说Vue 包含一组观察数组的变异方法,所以它们也将会触发视图更新
push() //从末尾添加
pop() //从末尾移除
shift() //从首项移除
unshift() //从首项添加
splice() //要删除或插入的位置;要删除的项数;要添加的项
sort() //相当于是冒泡法
reverse() //反转
替换数组
变异方法 (mutation method),顾名思义,会改变被这些方法调用的原始数组。相比之下,也有非变异 (non-mutating method) 方法,例如:filter()
, concat()
和 slice()
。这些不会改变原始数组,但总是返回一个新数组。当使用非变异方法时,可以用新数组替换旧数组:
example1.items = example1.items.filter(function (item) {
return item.message.match(/Foo/)
})
当数组变了,那我们之前的应用了那个数组的内容的结构,会不会重新渲染呢?按道理是会的但是vue他就还是很NB的,Vue 为了使得 DOM 元素得到最大范围的重用而实现了一些智能的、启发式的方法,所以用一个含有相同元素的数组去替换原来的数组是非常高效的操作。
所以答案是不会
好了我们回来我们如何解决上面的两个问题呢?
1.不可以直接通过索引(key,属性名)去改变值
2.不可以直接修改长度
方法
解决第一种的方法,也就是改变了,一样会更新是
// Vue.set
Vue.set(vm.items, indexOfItem, newValue)
// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)
参数:1:那个对象(数组),2:那一个属性(key),3:属性值(value)
你也可以使用 vm.$set
实例方法,该方法是全局方法 Vue.set
的一个别名:
vm.$set(vm.items, indexOfItem, newValue)
解决第二种的方法
vm.items.splice(newLength)
案例(官方):
var vm = new Vue({
data: {
userProfile: {
name: 'Anika'
}
}
})
你可以添加一个新的 age 属性到嵌套的 userProfile 对象:
Vue.set(vm.userProfile, 'age', 27)
但当你需要添加多的属性的时候怎么办呢?set多下(这样其实是不好)
vm.userProfile = Object.assign({}, vm.userProfile, {
age: 27,
favoriteColor: 'Vue Green'
})
注意这里的写法是不一样的,那我们关于检测变化就先到这里了
异步更新队列
那什么是异步更新队列呢?就是说我一个数据发生了更新并不是立马就更新了而是由一个过程,我们可以在这里给一个异步的回调函数Vue.nextTick(callback),(个人理解大佬,可以给点反馈/呵呵)
官方的案例是
<div id="example">{{message}}</div>
var vm = new Vue({
el: '#example',
data: {
message: '123'
}
})
vm.message = 'new message' // 更改数据
vm.$el.textContent === 'new message' // false
Vue.nextTick(function () {
vm.$el.textContent === 'new message' // true
})
这里案例就可以很好的说明了,数据其实不是立马更新的,那么是一个什么样的过程呢?
Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据改变。如果同一个 watcher 被多次触发,只会被推入到队列中一次。这种在缓冲时去除重复数据对于避免不必要的计算和 DOM 操作是非常重要的。然后,在下一个的事件循环“tick”中,Vue 刷新队列并执行实际 (已去重的) 工作
例如:
html
<div id="example">
<span>{{mes}}</span>
<span>{{message}}</span>
</div>
js
var vm = new Vue({
el: '#example',
data: {
message: '123',
mes: '123',
}
})
vm.message = 'new message';// 更改数据
vm.message = 'newnew message';
console.log(vm.$el.textContent === 'new message')// false
Vue.nextTick(function () {
console.log(vm.$el.textContent === 'new message') // false
vm.$el.textContent // 123 newnew message
})
这里页面最后渲染的是 123 newnewmessage,从而对应来上文
这里还有一个地方需要注意的就是vm.$el.textContent他是什么东西,我在案例中已经打印了你们可以看一下你们就知道了,我认为我el中全部的innerhtml({{}})中的值
好了到这里vue的响应式原理到这里也差不多了,希望对大家有帮助,也希望文中有问题大家可以指出我给予改正