Vue双向绑定原理及实现方法
1. 什么是Vue双向绑定
双向绑定是Vue框架重要的特点之一,意味着当数据发生改变时,视图会随之发生变化,同时视图的修改也会同步到数据中。这种机制使得开发者只需要关注逻辑的实现而不用担心数据如何与视图同步,便于提高开发效率和减少出错概率。
2. 双向绑定原理
Vue中的双向绑定原理主要是通过以下几个步骤实现的:
- 数据劫持
首先,在Vue框架被初始化时,Vue会对传入的data数据进行遍历,将所有属性(包括嵌套属性)使用Object.defineProperty()
方法进行劫持,以便在属性被读取或者被修改时能够监听到。
function defineReactive(data, key, val) {
Object.defineProperty(data, key, {
enumerable: true, // 是否可枚举
configurable: true, // 是否可删除
get: function() {
//...
},
set: function(newVal) {
//...
}
})
}
以上代码为数据劫持的具体实现。
- 数据的观察者Watcher
接下来,对于每个被劫持的属性,都需要为其创建一个观察者Watcher。Watcher主要负责监听该属性的变化,如果变化则通知Dep(下面介绍),进而触发相应的回调。
function defineReactive(data, key, val) {
let dep = new Dep() // 一个属性对应一个dep对象
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get: function() {
if (Dep.target) {
dep.depend() // watcher向dep对象添加自己
}
//...
},
set: function(newVal) {
dep.notify() // dep对象通知所有依赖于它的watcher更新状态
//...
}
})
}
以上代码为定义观察者Watcher的具体实现。
- 观察者的订阅者Dep
观察者的订阅者Dep主要负责收集各个观察者Watcher,以便于在数据变化的时候,通知所有依赖于该数据的观察者Watcher进行更新。
class Dep {
constructor() {
this.subs = []
}
addSub(sub) {
this.subs.push(sub)
}
removeSub(sub) {
remove(this.subs, sub)
}
depend() {
if (Dep.target) {
Dep.target.addDep(this)
}
}
notify() {
const subs = this.subs.slice() // 浅复制,保护this.subs数组
for (let i = 0, l = subs.length; i < l; i++) {
subs[i].update()
}
}
}
Dep.target = null // 静态属性,watcher的全局存储
以上代码为观察者的订阅者Dep的具体实现。
- 解析模板,建立Watcher
在Vue中,数据与视图之间的绑定通过Vue实例的$watch方法实现。
当Vue实例被创建时,会对所有的模板进行解析,建立一个Watcher实例,并且将Watcher实例添加到属性的依赖队列中。
class Watcher {
constructor() {
this.deps = []
}
addDep(dep) { // 向dep对象注册watcher
this.deps.push(dep)
dep.addSub(this)
}
update() { // 数据改变,视图刷新
//...
}
}
3. 双向绑定实现方法
3.1 Vue 1.x版本双向绑定实现方法:
Vue 1.x版本的双向绑定主要依靠ng-model指令实现,相关代码如下:
<input type="text" v-model="message">
Vue 1.x版本在接收到上述代码的时候,会自动生成以下的代码:
<input
type="text"
value="{{message}}"
oninput="__set_data(message, $event.target.value)"
>
其中,__set_data
方法是定义在Vue上的一个私有方法,其实现原理如下:
function makeSetter(exp) {
return new Function('‘value‘', '‘return this.’ + exp + '=value‘')
}
Vue.prototype.__set_data = function(exp, val) {
var setter = makeSetter(exp)
return setter.call(this, val)
}
以上代码为Vue 1.x版本的双向绑定实现方法。
3.2 Vue 2.x版本双向绑定实现方法:
Vue 2.x版本的双向绑定主要借助于Object.defineProperty()方法和响应式设计模式实现。相关代码如下:
<input type="text" v-model="message">
对应的Vue实例代码:
var vm = new Vue({
el: '#app',
data: {
message: ''
}
})
当输入框中的文本发生变化时,Vue实例会将新值赋值给message变量,然后通过$set方法通知视图进行改变。
Object.defineProperty(vm, key, {
get: function() {
//...
},
set: function(newVal) {
if (newVal === val) {
return;
}
val = newVal;
dep.notify(); // 数据变化通知所有依赖的观察者进行更新
}
});
以上代码为Vue 2.x版本的双向绑定实现方法。
4. 示例说明
4.1 Vue 2.x版本示例
<div id="app">
<input type="text" v-model="message">
<p v-text="message"></p>
</div>
对应的Vue实例代码:
var vm = new Vue({
el: '#app',
data: {
message: ''
}
})
在上面的示例中,当输入框中的文本发生变化时,Vue实例会将新值赋值给message变量,然后触发视图中的相应指令进行更新。
4.2 Vue 1.x版本示例
<div id="app">
<input type="text" ng-model="message">
<p>{{message}}</p>
</div>
对应的Vue实例代码:
var vm = new Vue({
el: '#app',
data: {
message: ''
}
})
在上面的示例中,当输入框中的文本发生变化时,Vue会自动生成相应的指令,刷新视图。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Vue双向绑定原理及实现方法 - Python技术站