vue2 的双向绑定原理是什么
-
Vue2 的双向绑定原理主要是通过使用 Object.defineProperty() 方法来劫持对象的属性,实现数据劫持,从而达到监听数据变化的目的。
具体步骤如下:
-
对于待观测的数据对象,Vue 会遍历对象的属性,并使用 Object.defineProperty() 方法将每个属性转换为“响应式属性”。这样一来,这些属性就可以被 Vue 监听到。
-
在使用 Object.defineProperty() 方法转换属性时,会为每个属性创建一个“依赖收集器”,用来存储属性的订阅者列表。在属性的 getter 方法中,会将当前的订阅者添加到依赖收集器中。
-
当属性发生变化时,会触发属性的 setter 方法。在 setter 方法中,会通知依赖收集器中的所有订阅者进行更新。
-
订阅者在更新时,会通知 Vue 响应式系统,并触发更新队列。Vue 会进行优化,将多次的更新合并成一次,以提高性能。
-
更新队列中的更新操作会导致视图进行重新渲染,达到数据和视图的同步更新。
总的来说,Vue2 的双向绑定原理就是通过数据劫持和观察者模式来实现的。通过劫持对象的属性,当属性发生变化时,会自动通知所有相关的订阅者进行更新,从而实现了数据的自动同步更新到视图上。这种机制使得开发者可以更方便地操作数据,并且不需要手动去更新视图,提高了开发效率。
2年前 -
-
Vue2的双向绑定原理主要基于 数据劫持和观察者模式。
-
数据劫持:Vue在初始化时会对数据对象进行遍历,使用Object.defineProperty()方法将每个属性转化为getter和setter。在getter函数中,首先进行依赖收集,将当前的观察者对象(即Watcher对象)添加到依赖中,然后返回属性的值。在setter函数中,首先将新的值与旧的值进行比较,如果发生变化则触发相应的更新操作,通知依赖的观察者对象进行更新。
-
观察者模式:Vue使用观察者模式来实现双向绑定。数据对象的每个属性都会对应一个Dep对象,Dep对象用来存储依赖的观察者对象。每个观察者对象都是一个Watcher实例,Watcher对象会在创建时将自身赋值给Dep.target,在getter函数中触发依赖收集时,将Dep.target添加到Dep对象中。当数据发生变化时,setter函数会通知Dep对象,Dep对象会遍历所有依赖的观察者对象并调用其update()方法进行更新操作。
-
模板编译:Vue的模板编译过程是将模板字符串转化为渲染函数,渲染函数是一个函数,它接受一个参数h,并返回一个VNode节点。在编译过程中,Vue会解析模板中的指令和插值表达式,将其转化为相应的渲染函数,这样在数据发生变化时,就可以通过触发渲染函数来更新视图。
-
依赖收集:在模板编译过程中,对模板中的每个表达式都会创建一个Watcher对象,Watcher对象会在初始化时触发一次表达式的求值,从而触发对应属性的getter函数,并将Watcher对象添加到Dep对象中进行依赖收集。这样在数据发生变化时,就可以通过依赖收集机制找到所有依赖该属性的观察者对象,并进行相应的更新操作。
-
活性更新:当数据发生变化时,触发setter函数,通知依赖的观察者对象进行更新。在更新过程中,Vue会根据虚拟DOM的比对算法,只更新实际发生变化的部分,从而提高性能和效率。
总结起来,Vue2的双向绑定原理是基于数据劫持和观察者模式实现的,通过数据劫持来监听属性的变化,通过观察者模式来建立属性与依赖的关系,并在数据变化时通知依赖进行更新。这样就实现了视图与数据的双向绑定。
2年前 -
-
Vue2 的双向绑定原理是基于数据劫持和发布-订阅模式实现的。下面将从劫持数据和监听数据变化两个方面来解析双向绑定原理。
- 劫持数据
Vue2 在初始化时会对数据对象进行递归遍历,将每个属性都通过 Object.defineProperty 方法转换为 getter 和 setter,并且在需要监听的属性上添加了一个 Watcher 对象。当数据被访问时,会触发 getter 方法,这时候可以收集订阅者到订阅者列表中。当数据被修改时,会触发 setter 方法,这时候可以通知订阅者更新视图。
下面是一个简单的例子,展示了数据劫持的实现:
function defineReactive(data, key, val) { Object.defineProperty(data, key, { enumerable: true, configurable: true, get: function() { // 如果当前有订阅者,将其添加到订阅者列表中 if (Dep.target) { dep.addSub(Dep.target); } return val; }, set: function(newVal) { if (val === newVal) { return; } val = newVal; // 通知订阅者更新视图 dep.notify(); } }); } function observer(data) { if (!data || typeof data !== 'object') { return; } Object.keys(data).forEach(function(key) { defineReactive(data, key, data[key]); }); } // 订阅者 function Watcher(vm, exp, callback) { this.vm = vm; this.exp = exp; this.callback = callback; this.value = this.get(); } Watcher.prototype = { update: function() { var value = this.get(); if (this.value !== value) { this.value = value; this.callback.call(this.vm, value); } }, get: function() { // 设置当前订阅者为 Dep.target,进行订阅者收集 Dep.target = this; var value = this.vm.$data[this.exp]; // 清空当前订阅者 Dep.target = null; return value; } }; // 订阅者列表 function Dep() { this.subs = []; } Dep.prototype = { addSub: function(sub) { this.subs.push(sub); }, notify: function() { this.subs.forEach(function(sub) { sub.update(); }); } }; // 使用示例 var data = { name: 'John' }; observer(data); new Watcher(data, 'name', function(value) { console.log('Name updated: ', value); }); data.name = 'Mike'; // 输出 'Name updated: Mike'- 监听数据变化
Vue2 中采用了观察者模式,在数据劫持的过程中,会为每个属性创建一个监听器,用于监听数据的变化。在收集订阅者时,会将订阅者添加到相应属性的监听器中。当数据发生变化时,会通知相应属性的监听器,从而触发订阅者的更新。
上述代码中的 Dep 类就是一个用于收集订阅者并触发更新的监听器。在劫持数据时,每一个属性都会创建一个 Dep 对象,用于收集订阅者。当数据变化时,会调用 Dep 对象的 notify 方法,通知所有订阅者进行更新。
另外,需要注意的是,Vue2 的双向绑定只会对使用了指令(v-model) 或者模板中使用的数据进行双向绑定,其他的数据不会进行双向绑定。
综上所述,Vue2 的双向绑定原理是通过数据劫持和发布-订阅模式实现的。数据劫持实现了对数据的 getter 和 setter 的劫持,以及订阅者的收集和触发;而发布-订阅模式实现了对数据变化的监听和订阅者的更新。通过这两者的配合,实现了数据的双向绑定。
2年前