Foreword
When creating a Vue instance, Vue will traverse the properties of data and convert them into getters/setters through ES5's Object.defineProperty. Internally, Vue can track dependencies and notify changes.
const vm = new Vue({ data: {foo: 1} // 'vm.foo' (在内部,同 'this.foo') 是响应的 })
Observe property changes
Vue instances provide the $watch method for observing property changes.
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
When the property changes, the response function will be called, and internally, this is automatically bound to the Vue instance vm.
It should be noted that the response is asynchronous.
As follows:
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
The binding of data and views is achieved through $watch Vue. When data changes are observed, Vue updates the DOM asynchronously. Within the same event loop, multiple data changes will be cached. In the next event loop, Vue refreshes the queue and only performs necessary updates.
is as follows:
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
Computed property
MV* In MV*, when the Model layer data is displayed to View, there is often complex data processing logic. In this case, it is more convenient to use computed property wise.
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²"
Inside a computed property, this is automatically bound to vm, so you need to avoid using arrow functions when declaring computed properties.
In the above example, vm.width and vm.height are responsive. When vm.area reads this.width and this.height for the first time, Vue collects them as dependencies of vm.area. After that, vm.width or When vm.height changes, vm.area is re-evaluated. Computed properties are based on its dependency cache. If vm.width and vm.height do not change, reading vm.area multiple times will immediately return the previous calculation results without having to evaluate again.
Similarly because vm.width and vm.height are responsive, in vm.area you can assign the dependent properties to a variable, and read the variables to reduce the number of times of reading properties, and at the same time solve the conditional branch, Vue Sometimes dependencies cannot be collected.
The implementation is as follows:
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²"
Use Vue’s attribute observation module alone through ob.js
To facilitate learning and use, ob.js extracts and encapsulates the attribute observation module in Vue.
ob.js GitHub address: https://github.com/cnlon/ob.js
Installation
npm install --save ob.js
Observe property changes
const target = {a: 1} ob(target, 'a', function (newValue, oldValue) { console.log(newValue, oldValue) // 3 1 }) target.a = 3
Add calculated properties
const target = {a: 1} ob.compute(target, 'b', function () { return this.a * 2 }) target.a = 10 console.log(target.b) // 20
Pass in the parameter set just like declaring a Vue instance
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