js变量与节点双向绑定

由 夕空 撰写于  2020年2月3日
<html>
<body>
<h1 ng-bind="num"></h1>
<input id="text"/>
</body>

<script>

//缓存
let watchers = {};
let scope = {};

//绑定变量
function watch(obj){
scope=obj;
const propertys = Object.keys(scope);

propertys.forEach(function (prop){
//console.log(prop);
//不处理函数属性
if( 'function' == typeof scope[prop] ) return;

const propName = prop;
console.log(propName, scope[prop]);
//监听对象属性
Object.defineProperty(scope, prop, {
//value: scope[prop],
configurable: true,
get: function() {
//scope[property]会导致栈溢出,因为一直递归(Uncaught RangeError: Maximum call stack size exceeded)
//console.log('get', prop, 'for', propName);
return watchers[propName];
},
set: function(value) {
//scope[property]会导致栈溢出,因为一直递归(Uncaught RangeError: Maximum call stack size exceeded)
//console.log('set', prop, 'for', propName);
//防止递归导致的栈溢出,先去掉监听的函数
document.removeEventListener('DOMCharacterDataModified', element);
document.removeEventListener('DOMNodeInserted', element);
watchers[prop] = value;
document.querySelector("*[ng-bind='"+prop+"']").innerText = watchers[prop];
//重新监听
document.addEventListener('DOMCharacterDataModified', element,false);
document.addEventListener('DOMNodeInserted', element,false);
}
});
});
}

//dom的修改触发JS变量的修改
function element(e){
console.log(e.newValue, e.prevValue, e.path);
const attrs = e.target.parentElement.attributes;
for(let i=0; i<attrs.length; i++){
const attr = attrs[i];
if('ng-bind' === attr.nodeName){
console.log('ng-bind:', scope[attr.nodeValue]);
scope[attr.nodeValue] = e.target.nodeValue;
}
}
}
//绑定从dom到js
document.addEventListener('DOMCharacterDataModified', element,false);
document.addEventListener('DOMNodeInserted', element,false);

</script>

<script>

//实际数据
var myData = {
num: 0
};
//绑定:从js到dom
watch(myData);
myData.num = 2; // set:2
console.log(myData.num); // get:2

//通过输入框修改变量
document.getElementById('text').oninput = function(e){
const v = document.getElementById("text").value;
const prop = 'num';
document.querySelector("*[ng-bind='"+prop+"']").innerText = v; //改变DOM
// myData.num = v; //改变变量
console.log('myNum:'+myData.num)
}
</script>
</html>

为了方便使用,对代码进行了封装:

//============================变量 dom 双向绑定
/*
* 夕空 flashme.cn 2020-6-5
var obj={}
var watch = new watchdata();
watch.inputevent(); //绑定input变化
watch.domevent(); //绑定dom变化
watch.setwatch(obj);
obj.aaa="hello world!"
<span ng-bind="aaa"></span>
*/

var watchdata = function () {
//缓存
let watchscope = {};
let domeve=false;
//绑定变量
return {
setwatch: function (obj) {
var than = this;
let watchers = {};
watchscope = obj;
const propertys = Object.keys(watchscope);

propertys.forEach(function (prop) {
//不处理函数属性
if ('function' == typeof watchscope[prop]) return;

const propName = prop;
// console.log(propName, watchscope[prop]);
//监听对象属性
Object.defineProperty(watchscope, prop, {
//value: watchscope[prop],
configurable: true,
get: function () {
//console.log('get', prop, 'for', propName);
return watchers[propName];
},
set: function (value) {
//防止递归导致的栈溢出,先去掉监听的函数
domeve && document.removeEventListener('DOMCharacterDataModified', than.element);
domeve && document.removeEventListener('DOMNodeInserted', than.element);
watchers[prop] = value;
var dom = document.querySelector("*[ng-bind='" + prop + "']")
dom.innerText = watchers[prop];
dom.value = watchers[prop];
//重新监听
domeve && document.addEventListener('DOMCharacterDataModified', than.element, false);
domeve && document.addEventListener('DOMNodeInserted', than.element, false);
}
});
});
},

element: function (e) {
//dom的修改触发JS变量的修改
// console.log(e.newValue, e.prevValue, e.path);
const attrs = e.target.parentElement.attributes;
for (let i = 0; i < attrs.length; i++) {
const attr = attrs[i];
if ('ng-bind' === attr.nodeName) {
watchscope[attr.nodeValue] = e.target.nodeValue;
}
}
},
domevent: function () {
domeve=true;
//绑定DOM的修改关联
document.addEventListener('DOMCharacterDataModified', this.element, false);
document.addEventListener('DOMNodeInserted', this.element, false);
},
inputevent: function () {
//绑定input表单的修改关联
var input=document.querySelectorAll("input[ng-bind]")
for(var k in input){
input[k].oninput = function (e) {
watchscope[e.target.attributes["ng-bind"].nodeValue] = e.target.value;
}
}

}
}

}



声明:星耀夕空|版权所有,违者必究|如未注明,均为原创|本网站采用BY-NC-SA协议进行授权

转载:转载请注明原文链接 - js变量与节点双向绑定


欢迎光顾我的小站!