之前面试过几个前端,问到vue数据绑定的原理时几乎都说了 拦截get set,但是数据怎么跟dom打交道却是说不清楚。
心血来潮 ,写个小demo,使用的是遍历数据的方式。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app">
<input type="text" name="" data-model="inputvalue" id="input1">
<input type="text" name="" data-model="inputvalue" id="input2">
<h3 data-model="inputvalue" id="h1"></h3>
<input type="button" data-click="changedate" value="click" />
</div>
<script>
let olddata = {};
let newdata = {
inputvalue: "inputvalue"
};
let watchers = {};
let methods = {
changedate: function () {
newdata["inputvalue"] = new Date().toLocaleTimeString();
}
}
//遍历数据
function diffData() {
Object.keys(newdata).forEach(key => {
for (let key in newdata) {
var newvalue = newdata[key];
var oldvalue = olddata[key];
debugger
if (newvalue !== oldvalue) {
olddata[key] = newvalue;
let handlers = watchers[key] || [];
handlers.forEach(handler => {
try {
handler(newvalue);
}
catch (e) {
console.log(e);
}
})
}
}
})
}
//遍历数据
function diffThread() {
setTimeout(() => {
diffData();
diffThread();
}, 10);
}
//有value的处理
function inputhandler(element) {
let newelement = element;
return function (newvalue) {
if (newelement.value !== newvalue) {
newelement.value = newvalue
}
}
}
//其它的值
function texthandler(element) {
let newelement = element;
return function (newvalue) {
newelement.innerText = newvalue;
}
}
//解析dom
function initDoms(doms) {
console.log(doms)
for (let i = 0; i < doms.length; i++) {
let element = doms[i];
console.log(element);
debugger
let key = element.dataset.model;
if (typeof key != 'undefined') {
if (typeof watchers[key] == 'undefined')
watchers[key] = [];
if (element.localName == 'input') {
//添加监听事件
element.addEventListener("keyup", (e) => {
let input = e.target;
newdata[input.dataset.model] = input.value;
});
//添加更新处理方法
watchers[key].push(inputhandler(element));
}
else {
//添加更新处理方法
watchers[key].push(texthandler(element));
}
}
let clickkey = element.dataset.click;
if (typeof clickkey != 'undefined') {
//添加事件监听
element.addEventListener("click", (e, ev) => {
methods[clickkey]();
})
}
//递归处理
arguments.callee(element.children);
}
}
//初始化
function init(id) {
let doms = document.getElementById(id).children;
initDoms(doms);
diffThread();
}
//初始化
init("app");
</script>
</body>
</html>