const App = {
data: reactive({
name: "123",
}),
template: `<div>我是Vue3<span>我在它里面</span></div>`,
};
function reactive(data) {
return new Proxy(data, {
get: (target, key) => {
if (target.hasOwnProperty(key)) {
return target[key];
}
},
set: (target, key, value) => {
target[key] = value;
render(target);
},
});
}
function render(data, documentId) {
console.log(data.data.name);
const vnode = compile(data.template)();
console.log(vnode);
function createRender(vnode) {
const el = document.createElement(vnode.tag);
for (const key in vnode.props) {
if (key.startsWith("on")) {
el.addEventListener(key.slice(2), vnode.props[key]);
}
}
vnode.children.forEach((node) => {
if (typeof node == "string") {
el.textContent = node;
} else {
el.appendChild(createRender(node));
}
});
return el;
}
document.getElementById(documentId).appendChild(createRender(vnode));
}
function compile(template) {
// 1. 将模板字符串转换为 HTML 元素
const tempDiv = document.createElement("div");
tempDiv.innerHTML = template;
const el = tempDiv.firstChild;
// 2. 递归解析 HTML 元素,生成虚拟 DOM
function _compile(node) {
if (node.nodeType === Node.TEXT_NODE) {
// 处理文本节点
return node.textContent;
}
// 处理元素节点
const vNode = {
tag: node.tagName.toLowerCase(),
props: {},
children: [],
};
// 获取属性
for (let i = 0; i < node.attributes.length; i++) {
const attr = node.attributes[i];
vNode.props[attr.name] = attr.value;
}
// 递归处理子节点
for (let i = 0; i < node.childNodes.length; i++) {
vNode.children.push(_compile(node.childNodes[i]));
}
return vNode;
}
// 3. 返回生成虚拟 DOM 的函数
return () => _compile(el);
}
render(App, "app");
手写Vue3
最新推荐文章于 2024-08-15 10:38:47 发布