响应系统是 Vue 一个显著功能,修改属性,能够更新视图,这让状态管理变得很是简单且直观。
建立 Vue 实例时,Vue 将遍历 data
的属性,经过 ES5 的 Object.defineProperty
将它们转为 getter/setter,在其内部 Vue 能够追踪依赖、通知变化。javascript
const vm = new Vue({ data: {foo: 1} // 'vm.foo' (在内部,同 'this.foo') 是响应的 })
Vue 的实例提供了 $watch
方法,用于观察属性变化。java
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
上。
须要注意的是,响应是异步的。以下:react
const vm = new Vue({ data: {foo: 1} }) vm.$watch('foo', function (newValue, oldValue) { console.log('inner:', newValue) // 后输出 "inner" 2 }) vm.foo = 2 console.log('outer:', vm.foo) // 先输出 "outer" 2
经过 $watch
Vue 实现了数据和视图的绑定。观察到数据变化,Vue 便异步更新 DOM ,在同一事件循环内,屡次数据变化将会被缓存起来,在下次事件循环中,Vue 刷新队列并仅执行必要的更新。以下:git
const vm = new Vue({ data: {foo: 1} }) vm.$watch('foo', function (newValue, oldValue) { console.log('inner:', newValue) // 后只输出一次 "inner" 5 }) vm.foo = 2 vm.foo = 3 vm.foo = 4 console.log('outer:', vm.foo) // 先输出 "outer" 4 vm.foo = 5
MV* 中,将 Model 层数据展示到 View,常常有复杂的数据处理逻辑,这种状况下,使用计算属性 (computed property) 更加明智。github
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.height output = area.toFixed(2) + 'm²' } return output } } }) vm.width = 2.34 vm.height = 5.67 console.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 有时会没法收集到依赖的问题。
新的实现以下:npm
const vm = new Vue({ data: { width: 0, height: 0, }, computed: { area () { let output = '' const {width, height} = this if (width > 0 && height > 0) { const area = width * height output = area.toFixed(2) + 'm²' } return output } } }) vm.width = 2.34 vm.height = 5.67 console.log(vm.area) // 输出 "13.27m²"
为方便学习和使用,smart-observe 将 Vue 中属性观察模块提取并封装了一下。缓存
smart-observe GitHub 地址:https://github.com/cnlon/smar...bash
安装异步
npm install --save smart-observe
观察属性变化函数
const target = {a: 1} observe(target, 'a', function (newValue, oldValue) { console.log(newValue, oldValue) // 3 1 }) target.a = 3
添加计算属性
const target = {a: 1} observe.compute(target, 'b', function () { return this.a * 2 }) target.a = 10 console.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 = observe.react(options) target.radius = 3
更详细的使用介绍请 点击这里
同时推荐其它两款同类库
Watch.JS https://github.com/melanke/Wa...
observe.js https://github.com/kmdjs/obse...