我想使用vanilla JavaScript实现双向数据绑定(如在Angular或Vue中(。
模型部分 I 的视图可以使用添加输入事件侦听器,和模型查看部分,我想使用Object.defineProperty的set函数。
在 defineProperty 的 set 函数中,我需要更改视图的值并设置属性值,但这会导致"超出最大调用堆栈大小",因为set property value
会一次又一次地递归运行。
现在的问题是:有没有办法同时使用 set 函数并设置其属性值?
现在我的代码:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>2 Way Data Binding</title>
</head>
<body>
text: <input id="text" class="text" type="text">
</body>
<script type="text/javascript">
var input = document.querySelector("#text");
var data = {};
Object.defineProperty(data, "text", {
get: function(){
return input.value
},
set: function(newValue){
input.value = newValue;
// data.text = newValue; // <------ this is the problem
}
})
input.input = function(){
data.text = data.text;
}
</script>
</html>
回答你的问题——不。如果你有一个二传手,你不能转身设置值而不循环。另一种方法是在对象上具有私有属性,只有 get()
和 set()
方法才能与之交互。外界将只使用具有 getter/setter 的属性。
不确定这是否是实现绑定的好方法,但这是一种提供使用 setter 设置属性的外观的方法:
const data = {
// _text is the source of truth
_text: "some text",
get text() {
return this._text
},
set text(newValue) {
input.value = newValue;
this._text = newValue;
}
};
const input = {
value: data.text
}
// original value
console.log(data.text)
console.log(input.value)
// change it
data.text = "other text"
console.log(data.text)
console.log(input.value)
在 setter 函数中,我需要设置属性值,但它会导致"超出最大调用堆栈大小",因为设置的属性值会一次又一次地递归运行。
是的。别这样。设置input.value
就足够了,getter 已经报告了新值。
当我控制台时.log我的视图模型(在上面的代码中是数据(,结果是{}(一个空对象(。所以说,如果我想迭代我的视图模型,那是做不到的。
嗯,这是一个非常不同的问题。这可以通过使属性可枚举来轻松解决:
var input = document.querySelector("#text");
var data = {};
Object.defineProperty(data, "text", {
enumerable: true,
get: function(){
return input.value
},
set: function(newValue){
input.value = newValue;
}
});
console.log(data);