Vue数据响应式怎么做到的

如何追踪变化

1. Object.defineProperty 把属性转为 getter/setter,用以检测数据的变化。
  • 当把一个普通的 JavaScript 对象传入 Vue 实例作为 data 选项,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property全部转为 getter/setter。
  • get 是一个函数,当属性被访问时,会触发 get 函数
  • set 也是一个函数,当属性被赋值时,会触发 set 函数,例如
var obj={    
    name:"响应式"
}
Object.defineProperty(obj,"name",{
    get(){        
        console.log("get 被触发")
    },
    set(val){        
        console.log("set 被触发")
    }
})
  • 当访问 obj.name 时,会打印 ' get 被触发 '
  • 当给 obj.name 赋值时,obj.name = 'xxx',会打印 ' set 被触发 '
2. watcher ,把组件渲染接触过的数据属性记为依赖
  • 每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。

由于 JavaScript 的限制,Vue 不能检测数组和对象的变化,解决方法是手动调用 Vue.set 或者 this.$set

1. 检测对象的变化
  • 对于已经创建的实例,Vue 不允许动态添加根级别的响应式 property。
var vm = new Vue({
  data:{
    a:1
  }
})

// `vm.a` 是响应式的

vm.b = 2
// `vm.b` 是非响应式的
  • 使用 Vue.set或者vm.$set (object, propertyName, value) 方法向嵌套对象添加响应式属性
Vue.set(vm.someObject, 'b', 2)   //Vue.set
this.$set(this.someObject,'b',2)    //vm.$set 实例方法,这也是全局 Vue.set 方法的别名
  • 有时可能需要为已有对象赋值多个新 property,比如使用 Object.assign() 或 _.extend()。但是,这样添加到对象上的新 property 不会触发更新。在这种情况下,你应该用原对象与要混合进去的对象的 property 一起创建一个新的对象。
// 代替 `Object.assign(this.someObject, { a: 1, b: 2 })`
this.someObject = Object.assign({}, this.someObject, { a: 1, b: 2 })
2. 检测数组的变化
  • 当你利用索引直接设置一个数组项和修改数组的长度时,Vue 不能检测到数组的变动:
  • 例如:
var vm = new Vue({
  data: {
    items: ['a', 'b', 'c']
  }
})
vm.items[1] = 'x' // 不是响应性的
vm.items.length = 2 // 不是响应性的
  • 利用索引直接设置一个数组项可以用对象的方式(Vue.set或者vm.$set (object, propertyName, value) ),也可以用splice方法
Vue.set(vm.items, indexOfItem, newValue) //Vue.set
vm.$set(vm.items, indexOfItem, newValue) //vm.$set
vm.items.splice(indexOfItem, 1, newValue) //splice
  • 修改数组的长度也可以用splice,splice在只有一个参数的时候表示保留的数组的长度
vm.items.splice(newLength)

异步更新队列

  • Vue 在更新 DOM 时是异步执行的
  • 只要侦听到数据变化,Vue 将开启一个队列,并缓冲在同一事件循环中发生的所有数据变更。如果同一个 watcher 被多次触发,只会被推入到队列中一次(会在缓冲时去除重复数据)
  • 所以如果想要在数据更新之后拿到数据,最好使用Vue.nextTick(callback)vm.$nextTick()实例方法
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容