当前位置 主页 > 服务器问题 > win服务器问题汇总 > 最大化 缩小

    Vue.js每天必学之内部响应式原理探究

    栏目:win服务器问题汇总 时间:2019-11-13 14:31

    深入响应式原理

    大部分的基础内容我们已经讲到了,现在讲点底层内容。Vue.js 最显著的一个功能是响应系统 —— 模型只是普通对象,修改它则更新视图。这让状态管理非常简单且直观,不过理解它的原理也很重要,可以避免一些常见问题。下面我们开始深挖 Vue.js 响应系统的底层细节。

    如何追踪变化

    把一个普通对象传给 Vue 实例作为它的 data 选项,Vue.js 将遍历它的属性,用 Object.defineProperty 将它们转为 getter/setter。这是 ES5 特性,不能打补丁实现,这便是为什么 Vue.js 不支持 IE8 及更低版本。

    用户看不到 getter/setters,但是在内部它们让 Vue.js 追踪依赖,在属性被访问和修改时通知变化。一个问题是在浏览器控制台打印数据对象时 getter/setter 的格式化不同,使用 vm.$log() 实例方法可以得到更友好的输出。

    模板中每个指令/数据绑定都有一个对应的 watcher 对象,在计算过程中它把属性记录为依赖。之后当依赖的 setter 被调用时,会触发 watcher 重新计算 ,也就会导致它的关联指令更新 DOM。

    变化检测问题

    受 ES5 的限制,Vue.js 不能检测到对象属性的添加或删除。因为 Vue.js 在初始化实例时将属性转为 getter/setter,所以属性必须在 data 对象上才能让 Vue.js 转换它,才能让它是响应的。例如:

    var data = { a: 1 }
    var vm = new Vue({
     data: data
    })
    // `vm.a` 和 `data.a` 现在是响应的
    
    vm.b = 2
    // `vm.b` 不是响应的
    
    data.b = 2
    // `data.b` 不是响应的
    
    

    不过,有办法在实例创建之后添加属性并且让它是响应的。

    对于 Vue 实例,可以使用 $set(key, value) 实例方法:

    vm.$set('b', 2)
    // `vm.b` 和 `data.b` 现在是响应的
    
    

    对于普通数据对象,可以使用全局方法 Vue.set(object, key, value):

    Vue.set(data, 'c', 3)
    // `vm.c` 和 `data.c` 现在是响应的
    
    

    有时你想向已有对象上添加一些属性,例如使用 Object.assign() 或 _.extend() 添加属性。但是,添加到对象上的新属性不会触发更新。这时可以创建一个新的对象,包含原对象的属性和新的属性:

    // 不使用 `Object.assign(this.someObject, { a: 1, b: 2 })`
    this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
    
    

    也有一些数组相关的问题,之前已经在列表渲染中讲过。

    初始化数据

    尽管 Vue.js 提供了 API 动态地添加响应属性,还是推荐在 data 对象上声明所有的响应属性。

    不这么做:

    var vm = new Vue({
     template: '<div>{{msg}}</div>'
    })
    // 然后添加 `msg`
    vm.$set('msg', 'Hello!')
    
    

    这么做:

    var vm = new Vue({
     data: {
     // 以一个空值声明 `msg`
     msg: ''
     },
     template: '<div>{{msg}}</div>'
    })
    // 然后设置 `msg`
    vm.msg = 'Hello!'
    
    

    这么做有两个原因:
     1.data 对象就像组件状态的模式(schema)。在它上面声明所有的属性让组件代码更易于理解。

     2.添加一个顶级响应属性会强制所有的 watcher 重新计算,因为它之前不存在,没有 watcher 追踪它。这么做性能通常是可以接受的(特别是对比 Angular 的脏检查),但是可以在初始化时避免。 

    异步更新队列

    Vue.js 默认异步更新 DOM。每当观察到数据变化时,Vue 就开始一个队列,将同一事件循环内所有的数据变化缓存起来。如果一个 watcher 被多次触发,只会推入一次到队列中。等到下一次事件循环,Vue 将清空队列,只进行必要的 DOM 更新。在内部异步队列优先使用 MutationObserver,如果不支持则使用 setTimeout(fn, 0)。

    下一篇:没有了