虚拟DOM和Diff算法

1 篇文章 0 订阅
1 篇文章 0 订阅

 虚拟DOM

虚拟DOM其实就是在真实DOM之前加了一层JS对象生成的DOM

  1. 用JS对象模拟DOM
  2. 把这个虚拟DOM对象转为真实的DOM插入到页面中
  3. 如果有事件修改了虚拟DOM,比较两个虚拟DOM树的差异,得到差异对象(补丁)
  4. 把差异对象应用到正则的DOM树上

 diff算法

  • Diff 比较两个虚拟DOM的区别(比较两个对象的区别)
  • 根据两个虚拟对象的区别,创建出补丁(patch),描述改变的内容,将这个补丁用来更新页面
  • 差异计算: 先序深度优先遍历

diff算法的三种优化策略

  1. 比较同级的节点(同一父节点的子节点)
    -  当发现节点已经不存在,则该节点及其子节点会被完全删除掉,不会用于进一步的比较。这样只需要对树进行一次遍历,便能完成整个DOM树的比较。对于不同层的节点,只有简单的创建和删除。
  2. 相同类型的节点比较:对属性进行重设实现节点的转换
renderA: <div style={{color: 'red'}} />
renderB: <div style={{fontWeight: 'bold'}} />
=> [removeStyle color], [addStyle font-weight 'bold']

 

 3. 列表节点的比较(key存在的意义)

  • 添加、删除、排序
  • 顺序的调整类似插入/删除    

模拟一个虚拟DOM

// 节点类
    class Element{
        constructor(type,props,children){
            this.type= type;
            this.props= props;
            this.children= children;
        }
    }
    // 生成节点类实例
    function createElement(type,props,children){
        return new Element(type,props,children)
    }

    // 创建一个虚拟DOM对象
    let virtualDOM= createElement('ul',{class: 'list'},[
        createElement('li',{class: 'item'},['a']),
        createElement('li',{class: 'item'},['b']),
        createElement('li',{class: 'item'},['c'])        
    ])
    console.log(virtualDOM)

    // 设置属性的方法
    function setAttr(node,key,value){
        switch(key){
            case 'value': // node是input或者textarea
                if(node.tagName.toUpperCase()=== 'INPUT' || node.tagName.toUpperCase()=== 'TEXTAREA'){
                    node.value= value
                }else{
                    node.setAttribute(key,value)
                }
                break;
            case 'style': 
                node.style.cssText= value;
                break;
            default: 
                node.setAttribute(key,value)        
                break;
        }
    }

    // render方法将vnode 转化成真实的dom
    function render(eleObj){
        let el= document.createElement(eleObj.type);    //生成父节点
        // 遍历父节点的props添加属性
        for(let key in eleObj.props){
            // 设置属性的方法
            setAttr(el,key,eleObj.props[key])
        }

        // 遍历父节点的children
        eleObj.children.forEach(item => {
            item= (item instanceof Element)? render(item) : document.createTextNode(item)    //创建文本节点
            el.appendChild(item)
        });
        return el
    }

    let el= render(virtualDOM)
    console.log(el)

    // 将元素插入到页面
    function renderDOM(el,target){
        target.appendChild(el)
    }
    renderDOM(el,document.body)

模拟Diff算法

未完待续。。。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值