博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

深入响应式原理

Posted on 2019-05-28 11:11  老烟枪47  阅读(165)  评论(0)    收藏  举报

深入响应式原理

2019年5月27号的这天我们学习了vue中的深入响应式原理

官方文档:

https://cn.vuejs.org/v2/guide/reactivity.html

如果追踪变化


当你把一个普通的javaScript对象传入Vue实例作为data选项,Vue 将遍历此对象所有的属性,幷使用object.defineProerty 把这些属性全部转换为getter/setter。Object.defineProerty是ES5中一个无法shim的特性,这也就是vue 不支持ie8以及更低版本游览器的原因。

这些getter/settr对用户来说是不可见的,但是在内部他们让vue能够追踪依赖,在属性被访问和修改时通知变更。这里需要注意的是不同的游览器在控制台打印数据对象时对gettr/setter的格式化幷不同,所以建议安装vue-devtools来获取对检查数据更加友好的用户界面。

每一个组件实例都对应一个watcher实例,他会在组件渲染的过程中吧“接触”过的数据属性记录为依赖。之后当依赖项的setter触发时,会通知watcher,从而使他们关联的组件重新渲染。
d536f4e4e849dc702e267d447fda4856.pngd536f4e4e849dc702e267d447fda4856.png

检测变化的注意事项


受现代javascript的限制(Object.observe 也已经被废除),vue 无法检测到对象属性的添加或删除。 由于vue会把初始化实例时对属性执行getter/setter转化,所以属性必须在 data 对象上存在才能让vue 将它转化成为响应式的。由于vue 会在初始化实例时对属性执行getter/setter转换,所以属性必须在data对象上存在才能让vue将它转化为响应式的。例如:

var vm = new Vue({
    data:{ 
        a : 1
    }

})

// `vm.a`是响应式

vm.b=2
//  vm.b 是非响应式的

对于已经创建的实例,vue 不允许动态添加根级别的响应式属性。但是,可以使用Vue.set(object , peopertName ,value)方法向嵌套对象添加响应式属性。例如,对于:

vue.set(vm.someObject,' b ' ,2

你还可以使用vm.$set实例方法,这也是全局Vue.set 方法的别名:

this.$sets (this.someObject,'b',2)

有时候你可能为有对象赋值多个新属性,比如使用object.assign()或· _.extend( ) .但是,这样添加到对象上的新属性不会触发更新。在这种情况下,你应该用原对象与要混合进行的对象的属性一起创建一个新的对象。

// 替代 ‘Object.assign(this.someObject,{a: 1 , b : 2})’

也有一些数组相关的注意事项,之前已经在列表渲染中讲过

声明响应式属性


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

var vm= new Vue({
data : {

///声明 message 为一个空值字符串
message :“   ” 
}
template :‘ <div>{{ 
message}}</div>’
})
vm.message = ' Hello'

如果你还未 data 选项中说明 message ,vue ,并且回调函数中的 this将自动绑定到当前的vue 实例上:

Vue.component('example', {
  template: '<span>{{ message }}</span>',
  data: function () {
    return {
      message: '未更新'
    }
  },
  methods: {
    updateMessage: function () {
      this.message = '已更新'
      console.log(this.$el.textContent) // => '未更新'
      this.$nextTick(function () {
        console.log(this.$el.textContent) // => '已更新'
      })
    }
  }
})

因为 $nextTick() 返回一个 Promise 对象,所以你可以使用新的 ES2016 async/await 语法完成相同的事情:

methods: {
  updateMessage: async function () {
    this.message = '已更新'
    console.log(this.$el.textContent) // => '未更新'
    await this.$nextTick()
    console.log(this.$el.textContent) // => '已更新'
  }
}