个人笔记-----vdom

149 阅读1分钟

最近看了有关vue3.0的视频 做些笔记

下面的内容都是在看完关于vue3.0的简介视频后自己手动敲完一遍

创建vnode

  1. 使用一个h函数生成js对象(vnode)
<div id="app"></div>
 /* 
    @params
        tag  String
        props  Object || null
        childer   String || Array 
     */

function h(tag, props, children) {
        return {
            tag,
            props,
            children
        }
    }

 const vdom = h('div', {
        class: 'red'
    }, [
        h('span', null, 'red')
    ])

挂载

1 写个挂载的函数吧

// 解析vnode 转换陈对于的元素或文本节点
function mount(vnode, container) {
        const el = vnode.el = document.createElement(vnode.tag)
        // props
        if (vnode.props) {
            for (let key in vnode.props) {
                const value = vnode.props[key]
                el.setAttribute(key, value)
            }
        }
        // children
        if (vnode.children) {
            if (typeof vnode.children === 'string') {
                el.textContent = vnode.children
            } else {
                console.log(1);
                vnode.children.forEach(child => {
                    mount(child, el)
                });
            }
        }
        container.appendChild(el)
    }
    mount(vdom, document.getElementById('app'))
  1. 做完这步就已经实现了一部分的效果 来看看效果吧

检查更新

  1. 检查更新是个比较复杂的就写了一个简单的
function patch(n1, 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 (newValue !== oldValue) {
                    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') {
                    if (newchildren !== oldChildren) {
                        el.textContent = newchildren
                    }
                } else {
                    el.textContent = newchildren
                }
            } else {

                if (typeof oldChildren === 'string') {
                    el.innerHTML = ''
                    newchildren.forEach(child => {
                        mount(child, el)
                    })
                } else {
                    const commonLength = Math.min(oldChildren.length, newchildren.length)
                    for (let i = 0; i < commonLength; i++) {
                         patch(oldChildren[i],newchildren[i])
                    }

                    if (newchildren.length > oldChildren.length) {
                        newchildren.slice(oldChildren.length).forEach(child => {
                            mount(child, el)
                        })
                    }else if(newchildren.length < oldChildren.length){
                        oldChildren.slice(newchildren.length).forEach(child => {
                            el.removeChild(chils.el)
                        })
                    }
                }
            }
        } else {
            // replace
           // ............
        }
    }
  1. 这里只写了元素相同下的一个对比 后续有空自己会去完成替换的内容

  2. 接下来看看结果

     const vdom2 = h('div', {
            class: 'green'
        }, [
            h('span', null, 'changed')
        ])
    
       patch(vdom, vdom2)