什么是双向数据绑定
- View(视图)的变化可以实时的让Model(数据)发生变化,同样的,Model的变化也是实时更新到View上。
- Vue2.x采用数据劫持和发布订阅模式实现双向数据绑定,通过ES5提供的
Object.defineProperty()
方法来劫持(监控)对象属性的getter
和setter
, 并在数据(对象)发生变动时通知订阅者,触发相应的监听回调。由于是在不同的数据上触发同步,可以精确的将变更发送给绑定的视图,而不是对所有数据都执行一次检测。
简易实现
1 | 手机号: <input id="tel" type="tel" /> |
Object.defineProperty()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32let obj = {
tel: null
};
let newObj = JSON.parse(JSON.stringify(obj));
Object.defineProperty(obj, 'tel', {
get() {
return newObj.tel;
},
set(val) {
if (val === newObj.tel) return;
newObj.tel = val;
observer();
}
});
function observer() {
document.getElementById('num').innerHTML = obj.tel;
document.getElementById('tel').val = obj.tel;
}
observer();
setTimeout(() => {
obj.tel = '15122222222';
}, 1000);
document.getElementById('tel').oninput = function () {
obj.tel = this.value;
}Proxy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26let obj = {};
obj = new Proxy(obj, {
get(target, prop) {
return target[prop];
},
set(target, prop, value) {
target[prop] = value;
observer();
}
});
function observer() {
document.getElementById('num').innerHTML = obj.tel;
document.getElementById('tel').val = obj.tel;
}
observer();
setTimeout(() => {
obj.tel = '15122222222';
}, 1000);
document.getElementById('tel').oninput = function () {
obj.tel = this.value;
}
差异比较
Object.defineProperty()
优点:
- 不需要显式的调用,Vue利用数据劫持和发布订阅,可以直接感知变化并且驱动视图
直接得到精确地变化数据,劫持了属性的
setter
,当属性值改变我们可以精确地获取变化的内容newVal
,不需要额外的diff
操作缺点:
- 不能监听数组:因为数组没有
getter
setter
,数组长度不确定,如果太长则影响性能 - 只能监听属性,而不是整个对象;需要遍历属性
只能监听属性变化,不能监听属性的删除
Proxy
优点:- 可以监听数据
- 可以监听整个对象(无需遍历)
- 13种拦截方法,很强大
返回新对象而不是直接修改原对象,更符合
immutable
缺点:
- 兼容性稍弱,无法使用
polyfill