mini-react実現原理解説第四講


文章は私のブログから始まりました.
https://github.com/mcuking/bl...
関連コードはhttps://github.com/mcuking/bl...を参照してください.
属性を更新
ここでは、diffアルゴリズムの概要について説明します.主に属性を更新する仕組みを紹介します.新しいvnodeのpropsと古いvnodeのpropsを比較して、
  • は、新しいDOMノード属性のみに存在するセットを見つけ、setAttrs(olddom、onlyInLeft)
  • を呼び出す.
  • は、旧DOMノード属性のみに存在するセットを見つけ、removeAttrs(olddom、onlyInRight)
  • を呼び出す.
  • 旧DOMノードと新しいDOMノードの両方に存在する属性のセットを見つけ、diffAttrs(olddom、bothIn.left、bothIn.right)
  • を呼び出す.
    //     
    const {onlyInLeft, onlyInRight, bothIn} = diffObject(vnode.props, olddom._vnode.props)
    setAttrs(olddom, onlyInLeft)
    removeAttrs(olddom, onlyInRight)
    diffAttrs(olddom, bothIn.left, bothIn.right)
    
    //    VNode    DOM              
    function diffObject(leftProps, rightProps) {
        const onlyInLeft = {} //       DOM        
        const onlyInRight = {} //       DOM        
        const bothLeft = {} //           DOM        
        const bothRight = {} //           DOM        
    
        for (let key in leftProps) {
            if (rightProps[key] === undefined) {
                onlyInLeft[key] = leftProps[key]
            } else {
                bothLeft[key] = leftProps[key]
                bothRight[key] = rightProps[key]
            }
        }
    
        for (let key in rightProps) {
            if (leftProps[key] === undefined) {
                onlyInRight[key] = rightProps[key]
            }
        }
    
        return {
            onlyInLeft,
            onlyInRight,
            bothIn: {
                left: bothLeft,
                right: bothRight
            }
        }
    }
    
    //    DOM     
    function setAttrs(dom, props) {
        for (let k in props) {
            //     className  ,   class
            if (k === 'className') {
                dom.setAttribute('class', props[k])
                continue
            }
    
            //     style  
            if (k === 'style') {
                if (typeof props[k] === 'string') {
                    dom.style.cssText = props[k]
                }
    
                if (typeof props[k] === 'object') {
                    for (let v in props[k]) {
                        dom.style[v] = props[k][v]
                    }
                }
                continue
            }
    
            //     on         
            if (k[0] === 'o' && k[1] === 'n') {
                dom.addEventListener(k.substring(2).toLowerCase(), props[k], false)
                continue
            }
    
    
            //         
            dom.setAttribute(k, props[k])
        }
    }
    
    //    DOM     
    function removeAttrs(dom, props) {
        for (let k in props) {
            if (k === 'className') {
                dom.removeAttribute('class', props[k])
                continue
            }
    
            if (k === 'style') {
                dom.style.cssText = ''
                continue
            }
    
            if (k[0] === 'o' && k[1] === 'n') {
                dom.removeEventListener(k.substring(2).toLowerCase(), props[k], false)
                continue
            }
    
            //         
            dom.removeAttribute(k, props[k])
        }
    }
    
    //    DOM     
    function diffAttrs(dom, newProps, oldProps) {
        for (let k in newProps) {
            if (newProps[k] === oldProps[k]) continue
    
            if (k === 'className') {
                dom.setAttribute('class', newProps[k])
                continue
            }
    
            if (k === 'style') {
                if (typeof newProps[k] === 'string') {
                    dom.style.cssText = newProps[k]
                }
    
                if (typeof newProps[k] === 'object' && typeof oldProps[k] === 'object') {
                    for (let v in newProps[k]) {
                        //       css         css     ,  css           css   
                        if (newProps[k][v] !== oldProps[k][v]) {
                            dom.style[v] = newProps[k][v]
                        }
                    }
    
                    //       css        ,      css       ,    css       
                    for (let v in oldProps[k]) {
                        if (newProps[k][v] === undefined) {
                            dom.style[v] = ''
                        }
                    }
                }
                continue
            }
    
            if (k[0] === 'o' && k[1] === 'n') {
                dom.removeEventListener(k.substring(2).toLowerCase(), oldProps[k], false)
                dom.addEventListener(k.substring(2).toLowerCase(), newProps[k], false)
                continue
            }
    
            //         
            dom.setAttribute(k, newProps[k])
        }
    }
    関連記事
  • mini-react実現原理解説第一話
  • mini-react実現原理解説第二話
  • mini-react実現原理解説第三講
  • mini-react実現原理解説第四講
  • mini-react実現原理解説第五話