[Vue] MIni mount and patch function

<style>
	.red {color: red;}
	.green {color: green;}
</style>

<div id="app"></div>

<script>
	function h(tag, props, children) {
		return { tag, props, children };
	}
	
	function mount(vnode, container) {
		const el = vnode.el = document.createElement(vnode.tag)
		
		console.log(vnode)
		
		// props
		if (vnode.props) {
			for (const key in vnode.props) {
				el.setAttribute(key, vnode.props[key])
			}
		}
		
		// children
		if (vnode.children) {
			if (typeof vnode.children === 'string') {
				el.textContent = vnode.children		
			} else {
				vnode.children.forEach(child => {
					mount(child, el)
				})
			}
		} 
		
		container.appendChild(el)
	}
	
	const vdom = h('div', {class: 'red'}, [
		h('span', null, 'hello')
	])
	
	mount(vdom, document.getElementById('app'))
	
	function patch(/*old vdom*/n1 , /*new vdom*/ n2 ) {
		if (
			n1.tag === n2.tag
		) {
			const el = n2.el = n1.el
			// props
			const oldProps = n1.props || {}
			const newProps = n2.props || {}
			for (const key in newProps) {
				const oldValue = oldProps[key]
				const newValue = newProps[key]
				if (oldValue !== newValue) {
					el.setAttribute(key, newValue)
				}
			}
			
			for(const key in oldProps) {
				if (!(key in newProps)) {
					el.removeAttribute(key)
				}
			}
			
			// children
			const oldChildren = n1.children
			const newChildren = n2.children
			if (typeof newChildren === 'string') {
				if (typeof oldChildren === 'string') {
					el.textContent = newChildren
				} else {
					// oldChildren is array
					el.textContent = newChildren
				}
			} else {
				// newChildren is array
				if (typeof oldChildren === 'string') {
					el.innerHTML = ''
					newChildren.forEach(child => {
						mount(child, el)
					})
				} else {
					// oldChildren is array
					// handle common children
					const commonLength = Math.min(oldChildren.length, newChildren.length)
					for (let i = 0; i < commonLength; i++) {
						patch(oldChildren[i], newChildren[i])
					}
					// newChildren is longer, handle new children
					if (newChildren.length > oldChildren.length) {
						newChildren.slice(oldChildren.length).forEach(child => {
							mount(child, el)
						})
					} else if (newChildren.length < oldChildren.length) {
						// oldChildren is longer, handle removed children
						oldChildren.slice(newChildren.length).forEach(child => {
							el.removeChild(child.el)
						})
					}
				}
			}
		} else {
			// replace
		}
	}
	
	const vdom2 = h('div', {class: 'green'}, [
	  h('span', null, 'changed!')
	])
	patch(vdom, vdom2)
</script>

 

posted @ 2024-12-03 15:08  Zhentiw  阅读(2)  评论(0编辑  收藏  举报