参考链接 www.bilibili.com/video/BV1LE…
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="root">
<p>firstName:{{ user.name.firstName }}</p>
<p>lastName:{{ user.name.lastName }}</p>
</div>
</body>
<script>
/**
* 通过路径 xx.yy.zz 访问一个对象并返回对应的值
* @param obj 选项里面的data
* @param path 路径
* @returns {*} 键值
*/
function getValueByPath(obj, path) {
let paths = path.split('.');
let res = obj;
let prop;
while (prop = paths.shift()) {
res = res[prop];
}
return res;
}
let rkuohao = /{{(.+?)}}/g;
/**
* 解析编译模板,并赋值
* @param template id="root" 的Dom元素
* @param data 选项里面的data
*/
function compiler(template, data) {
let childNodes = template.childNodes;
for (let i = 0; i < childNodes.length; i++) {
let type = childNodes[i].nodeType; // 1 元素, 3 文本节点
if (type === 3) {
let txt = childNodes[i].nodeValue;
txt = txt.replace(rkuohao, function (_, g) {
let path = g.trim(); // 写在双花括号里面的 东西
let value = getValueByPath(data, path);
return value;
});
childNodes[i].nodeValue = txt;
} else if (type === 1) {
compiler(childNodes[i], data);
}
}
}
class MyVue {
constructor(options) {
this._data = options.data;
this._el = options.el;
this._templateDOM = document.querySelector(this._el);
this._parent = this._templateDOM.parentNode;
this.render()
}
render() {
this.compiler();
}
compiler() {
let realHTMLDOM = this._templateDOM.cloneNode(true);
compiler(realHTMLDOM, this._data);
this.update(realHTMLDOM);
}
update(realHTMLDOM) {
this._parent.replaceChild(realHTMLDOM, document.querySelector('#root'));
}
}
let app = new MyVue({
el: '#root',
data: {
user: {
name: {
firstName: "张",
lastName: "三"
}
}
}
});
</script>
</html>