likes
comments
collection
share

vue响应式原理

作者站长头像
站长
· 阅读数 5

vue响应式原理

什么是响应式

vue最显著的特性之一便是不太引人注意的响应式系统(reactivity system)。

所谓的响应式,就是指模型层(model,只是普通 JavaScript 对象)发生变化了,就更新视图(view)

其实,就是前面提到的mvvm思想中来的单向数据绑定。

M,model发生了变化,那么我们的v,view随之更新。

典型的一些表现

  • 更新data中的数据,当前组件的视图更新
  • 更新data中的数据,计算属性也会更新
  • 更新data中的数据,传递到子组件中的数据也会更新

表现1:组件视图的响应

vue响应式原理

vue响应式原理

表现2:计算属性的响应

vue响应式原理

vue响应式原理

表现3:子组件的响应式

vue响应式原理

vue响应式原理

效果:

vue响应式原理

是不是说,只要data代理的数据发生的变化,我们的视图就一定会更新呢?

答案是否定,请看如下案例:

vue响应式原理

效果如下:

vue响应式原理

说明,这种情况不具备响应式特点,为什么呢?

其原因和vue.js的响应式原理有关系的。

响应式原理(面试)

把一个普通 JavaScript 对象传给 Vue 实例的 data 选项,Vue 将遍历此对象所有的属性,并使用 Object.defineProperty 把这些属性全部转为 getter/setter。

由于Object.defineProperty是es5中的方法,所以对于ie8及其以下的浏览器,vue.js是不支持的。

可以通过控制体查看这个信息:

vue响应式原理

每个组件实例都有相应的 watcher 实例对象,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher 重新计算,从而致使它关联的组件得以更新。

其图示如下:

vue响应式原理

这个模式,叫做观察者模式。

在这里,watcher监视data中代理的数据,一旦发生了变化,就会通知视图,进行更新操作。

为什么,刚才设置book的author属性,没有更新呢?

原因在于,book中并没有声明author属性,对应的就不存在getter和setters方法,所以,book中除name和price,其他任何的属性都没有列入观察的范围,所以就不具备响应特点。

基于这个响应式原理:受现代 JavaScript 的限制,Vue 不能检测到对象属性的添加或删除。

响应式细节

在使用vue.js来实现响应式,需要注意以下几点:

  • Vue不允许动态添加根级响应式属性,所以你必须在初始化实例前声明根级响应式属性,哪怕只是一个空值
  • 受现代JavaScript的限制,Vue不能检测到对象属性的添加或删除
  • 数组直接修改索引也不能被检测到
  • 可以使用 Vue.set(object, key, value) 方法将响应属性添加到嵌套的对象上
  • 还可以使用vm.$set实例方法,这也是全局 Vue.set 方法的别名
  • 父组件的对象传递给子对象,在子对象中可以修改该对象
  • Vue 异步执行 DOM 更新,为了在数据变化之后等待 Vue 完成更新 DOM,可以使用Vue.nextTick(callback)。

a.Vue不允许动态添加根级响应式属性,所以你必须在初始化实例前声明根级响应式属性,哪怕只是一个空值

如:

vue响应式原理

查看控制台如下:

vue响应式原理

b.受现代JavaScript的限制,Vue不能检测到对象属性的添加或删除,数组直接修改索引也不能被检测到

vue响应式原理

这个不会效果。

Vue.js提供了两种方式:

  • 可以使用 Vue.set(object, key, value) 方法将响应属性添加到嵌套的对象上
  • 还可以使用vm.$set实例方法,这也是全局 Vue.set 方法的别名

使用set,编写代码如下:

vue响应式原理

测试,ok。

针对数组,使用索引来修改,也不会有响应特点。

vue响应式原理

点击,不会发生变化,如下:

vue响应式原理

也是可以使用set来进行修改,如下:

vue响应式原理

效果如下:

vue响应式原理

c.父组件的对象传递给子对象,在子组件中可以修改该对象

在子组件中,修改传递的基本类型数据,是不允许的,如下:

vue响应式原理

如果是对象类型呢?

vue响应式原理

修改如下:

vue响应式原理

实际上,由于对象在传递的时候,是传递的地址,父子组件中的对象是指同一个对象。

所以,在子组件中,是可以去修改父组件传递过来的对象。

vue.sync

vue .sync 修饰符以前存在于vue1.0版本里,但是在在 2.0 中移除了 .sync 。 2.3.0 又重新引入了 .sync 修饰符。只是作为一个编译时的语法糖存在。它会被扩展为一个自动更新父组件属性的 v-on 监听器。

实际上,当子组件需要更新 foo 的值时,它需要显式地触发一个更新事件:

this.$emit('update:foo', newValue)

vue 修饰符sync的功能是:当一个子组件改变了一个 prop 的值时,这个变化也会同步到父组件中所绑定。如果不用.sync,也可以props传初始值,然后事件监听,实现起来也不算复杂。

d.Vue 异步执行 DOM 更新,为了在数据变化之后等待 Vue 完成更新 DOM。可以使用Vue.nextTick(callback)。

在vue.js中,model的变化,会导致视图发生更新,所谓视图更新,说白了,就是指dom更新。

但是,不要简单的认为这个更新操作是立刻完成。实际上,它是后续才完成的。

看着页面是发生变化了,变化的时刻并不是修改完数据的那一刻。

编写代码如下:

vue响应式原理

测试,如下:

vue响应式原理

说明,并不是一修改完这个msg,就立刻更新视图了。在vue.js中,它其实是进行了异步的更新操作。当前这种情况下,我们是无法在modify的操作中,获取更新之后的值。所以,针对这种情况,vue.js提供了一个nextTick的回调方法。

可以修改代码如下:

vue响应式原理