前言创建 Vue 实例时,Vue 将遍历 data 的属性,通过 ES5 的
Object.defineProperty
将它们转为 getter/setter,在其内部 Vue 可以追踪依赖、通知变化。
const vm = new Vue({ data: {foo: 1} // "vm.foo" (在内部,同 "this.foo") 是响应的})
观察属性变化Vue 的实例提供了 $watch 方法,用于观察属性变化。
const vm = new Vue({ data: {foo: 1}})vm.$watch("foo", function (newValue, oldValue) { console.log(newValue, oldValue) // 输出 2 1 console.log(this.foo) // 输出 2})vm.foo = 2
当属性变化后,响应函数将会被调用,在其内部,this 自动绑定到 Vue 的实例 vm 上。
需要注意的是,响应是异步的。如下:const vm = new Vue({ data: {foo: 1}})vm.$watch("foo", function (newValue, oldValue) { console.log("inner:", newValue) // 后输出 "inner" 2})vm.foo = 2console.log("outer:", vm.foo) // 先输出 "outer" 2
通过
$watch Vue
实现了数据和视图的绑定。观察到数据变化,Vue 便异步更新 DOM ,在同一事件循环内,多次数据变化将会被缓存起来,在下次事件循环中,Vue 刷新队列并仅执行必要的更新。
如下:const vm = new Vue({ data: {foo: 1}})vm.$watch("foo", function (newValue, oldValue) { console.log("inner:", newValue) // 后只输出一次 "inner" 5})vm.foo = 2vm.foo = 3vm.foo = 4console.log("outer:", vm.foo) // 先输出 "outer" 4vm.foo = 5
计算属性MV* 中,将 Model 层数据展现到 View,经常有复杂的数据处理逻辑,这种情况下,使用计算属性 (computed property) 更加明智。
const vm = new Vue({ data: { width: 0, height: 0, }, computed: { area () {let output = ""if (this.width > 0 && this.height > 0) {const area = this.width * this.heightoutput = area.toFixed(2) + "m²"}return output } }})vm.width = 2.34vm.height = 5.67console.log(vm.area) // 输出 "13.27m²"
在计算属性内部,this 自动绑定 vm,因此声明计算属性时需要避免使用箭头函数。
上例中,
vm.width
和
vm.height
是响应的,
vm.area
内部首次读取
this.width
和
this.height
时,Vue 收集其做为
vm.area
的依赖,此后
vm.width
或
vm.height
变化时,
vm.area
重新求值。计算属性是基于它的依赖缓存,如果
vm.width
和
vm.height
没有变化,多次读取
vm.area
,会立即返回之前的计算结果,而不必再次求值。
同样由于
vm.width
和
vm.height
是响应的,在
vm.area
中可以将依赖的属性赋值给一个变量,通过读取变量来减少读取属性次数,同时解决在条件分支中,Vue 有时会无法收集到依赖的问题。
实现如下:const vm = new Vue({ data: { width: 0, height: 0, }, computed: { area () {let output = ""const {width, height} = thisif (width > 0 && height > 0) {const area = width * heightoutput = area.toFixed(2) + "m²"}return output } }})vm.width = 2.34vm.height = 5.67console.log(vm.area) // 输出 "13.27m²"
通过 ob.js 单独使用 Vue 的属性观察模块为方便学习和使用,ob.js 将 Vue 中属性观察模块提取并封装了一下。
ob.js GitHub 地址:https://github.com/cnlon/ob.js
安装npm install --save ob.js
观察属性变化const target = {a: 1}ob(target, "a", function (newValue, oldValue) { console.log(newValue, oldValue) // 3 1})target.a = 3
添加计算属性const target = {a: 1}ob.compute(target, "b", function () { return this.a * 2})target.a = 10console.log(target.b) // 20
像声明 Vue 实例一样传入参数集合const options = { data: { PI: Math.PI, radius: 1, }, computed: { "area": function () {return this.PI * this.square(this.radius) }, }, watchers: { "area": function (newValue, oldValue) {console.log(newValue) // 28.274333882308138 }, }, methods: { square (num) {return num * num }, },}const target = ob.react(options)target.radius = 3
总结以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流。