0%

基于 Object.defineProperty() 的原生js双向数据绑定

前面我们介绍过存储器属性(重新认识JS对象(一)-- 对象及其属性),以及如何用Object.defineProperty()定义一个存储器属性,今天我们介绍如何用Object.defineProperty()实现双向数据绑定。

我们知道一个存储器属性有四个属性描述符:get,set,configurable,enumerable。我们来复习一下如何创建一个存储器属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
var user = {
name: ''
}
Object.defineProperty(user, 'nickname', {
configurable: true,
enumerable: true,
get: function() {
return this.name
},
set: function(value) {
this.name = value
}
})

以上代码我们给user创建了一个名为nickname的存储器属性。

接下来我们改写getset,让它们与DOM绑定,并实现双向数据绑定,以下为具体实现的伪代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<input type="text" id="foo">

<script>
var user = {}
Object.defineProperty(user, 'inputValue', {
configurable: true,
get: function() {
return document.getElementById('foo').value
},
set: function(value) {
document.getElementById('foo').value = value
}
})
</script>

我们打开控制台,改变user.inputValue的值,会发现input输入框里的值也发生变化;同样我们在input输入框里面输入值,在控制台打印user.inputValue,会发现user.inputValue也发生了变化。这样我们就实现了双向的数据绑定。

如果多个DOM绑定同一个数据,我们可以监听input输入框的keyup事件,只要触发了keyup事件我们就把user.inputValue的值赋给另一个DOM,具体实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<input type="text" id="foo">
<p id="test"></p>

<script>
var user = {}
Object.defineProperty(user, 'inputValue', {
configurable: true,
get: function() {
return document.getElementById('foo').value
},
set: function(value) {
document.getElementById('foo').value = value
document.getElementById('test').innerHTML = value
}
})
document.getElementById('foo').addEventListener('keyup',function() {
document.getElementById('test').innerHTML = user.inputValue
})

最后附上源码图片

思考:其实实现双向数据绑定并不一定要用Object.defineProperty(),其主要是运用存储器属性的get和set,以下代码也可以实现双向数据绑定:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<input type="text" id="foo">
<p id="test"></p>

<script>
var user = {
get inputValue() {
return document.getElementById('foo').value
},
set inputValue(value) {
document.getElementById('foo').value = value
document.getElementById('test').innerHTML = value
}
}
document.getElementById('foo').addEventListener('keyup',function() {
document.getElementById('test').innerHTML = user.inputValue
})
</script>