Open zwhu opened 6 years ago
<button id="update">update</button> <div id="root"></div>
let vdom1 = { tag: 'div', props: { style: 'border: solid 2px red;' }, children: [{ tag: 'a', props: { id: '1', href: 'http://test.com', target: '_blank' }, children: [{ text: 'click!' }] }, { text: 'text!!' }, { tag: 'div', props: { class: 'class1 class2', 'data-attr': 'hello' }, children: [{ text: 'hahaha!' }, { tag: 'br' }] }, { tag: 'br' }] }
let vdom2 = { tag: 'div', props: { class: 'vdom2' }, children: [{ tag: 'a', props: { id: '1', href: 'http://test.com', target: '_blank' }, children: [{ text: 'click!!!' }] }, { tag: 'h2', children: [{ text: 'hahahah!' }] }, { tag: 'div', props: { class: 'class1 class2', 'data-attr': 'hello' }, children: [{ text: 'xxixii!' }, { tag: 'br' }] }, { tag: 'br' }] }
let prev function render(container, root) { function dfs(node, prev = {}) { let element if (node.tag) { if (prev && prev.tag === node.tag) { element = prev.raw updateProps(element, node.props, prev.props) } else { element = createElement(node.tag, node.props) } node.children && renderChildren(node.children, prev.children, element) } else if (typeof node.text === 'string') { element = createTextNode(node.text) } node.raw = element return node } function renderChildren(children = [], prevChildren = [], parentElement) { children.forEach((child, index) => { let prevChild = null if (prevChildren) prevChild = prevChildren[index] if (prevChild) { let newNode = dfs(child, prevChild) if (prevChild.tag !== child.tag) { parentElement.replaceChild(newNode.raw, prevChild.raw) } } else { let newNode = dfs(child) parentElement.appendChild(newNode.raw) } }) prevChildren.slice(children.length).forEach((child) => { parentElement.removeChild(child.raw) }) } dfs(root, prev) if (!prev) { prev = root container.appendChild(prev.raw) } } function createElement(tag, props = {}) { const element = document.createElement(tag) updateProps(element, props) return element } function updateProps(element, props = {}, oldProps = {}) { Object.keys(oldProps).forEach((key) => { element.removeAttribute(key) }) Object.keys(props).forEach((key) => { element.setAttribute(key, props[key]) }) } function createTextNode(text) { return document.createTextNode(text) } let fake1 = render(root, vdom1) update.addEventListener('click', () => { fake2 = render(root, vdom2) })