Vue源码之虚拟DOM与Diff算法

一、虚拟DOM

1.1、h() ==》虚拟节点Vnode

h( sel , data ,c )
sel: 选择器 ; data:属性(class,id,key…); c:文本节点 或者 虚拟节点h()
返回虚拟节点:Vnode

  • 文件 h.js

    export default function(sel,data,c){
    	 if(arguments.length!=3){
    		throw new Error('传入的参数个数必须是三个');
    	 }else if(typeof c === 'string' || typeof c === 'number'){
    	    // h('div',{},'文字')
    	    return vnode(sel,data,undefined,c,undefined);
         }else if(Array.isArray(c) ){
    		 // h('div',{},[])
    	 	let children = [];
    	 	//  debugger
    	 	for(let i = 0;i<c.length;i++){  
      		 if(!(typeof c[i] === 'object' && c[i].hasOwnProperty('sel')))
         		 throw new Error('第三个参数的内嵌类型不对');
       			 children.push(c[i]);
    		  }
     		  return vnode(sel,data,children,undefined,undefined);
    		 }else if(typeof c ==='object' && c.hasOwnProperty('sel')){
    		    // h('div',{},h())
    		    let children = [c];
    		    return  vnode(sel,data,children,undefined,undefined); 
          	 }else{
    	        throw new Error('第三个参数类型不对');
             }
       }
    
  • 文件 vnode.js

    export default function(sel,data,children,text,elm){
     let key = data.key;
     return {sel,data,children,text,elm,key}
    }
    

1.2、将虚拟节点 上树(显现到界面上)

  • patch.js
    • 判断同一节点:选择器相同 && key 相同
export default function(oldVode,newVonde){
 // debugger
 // 判断oldVode 是否为虚拟节点
 if(oldVode.sel == '' || oldVode.sel === undefined){
   // 将dom 节点包装成虚拟节点
   oldVode = vnode(oldVode.tagName.toLowerCase(),{},[],undefined,oldVode) ;
 }
 // -------------上树 :同时进行 Diff 更新虚拟DOM------------------------              
 // 判断是否为同意节点
 if(oldVode.sel === newVonde.sel && oldVode.key === newVonde.key){
   console.log('是同一个节点');
   // 如果oldVode === newVonde Y:什么也不用
   patchVnode(oldVode,newVonde);
 }else{
   // 暴力插入新节点,删除旧节点 
   let newDom = createElement(newVonde);
   // 上树
   oldVode.elm.parentNode.insertBefore(newDom,oldVode.elm);
   // 删除老节点
   oldVode.elm.parentNode.removeChild(oldVode.elm);
 }
};
  • patchVnode.js
export default function patchVnode(oldVode,newVonde){
  if(oldVode === newVonde){
    // patch(myVonde1, myVonde1);
    return;
  }
  // patch(myVonde1, myVonde2);
  // 判断 newVonde 是否有文字属性:
  if(newVonde.text != undefined && (newVonde.children == undefined || newVonde.children.length ==0)){
    // newVnode有文字属性 
    console.log('新的虚拟节点有文字属性');
    if(newVonde.text != oldVode.text){
      oldVode.elm.innerText = newVonde.text;
    }    
  }else{
    // 新newVnode 有children 子节点
    if(oldVode.children!=undefined && oldVode.children.length>0){
      // 精细比较
      // newVnode 有children,oldVnode有children  
      console.log('newVnode 有children,oldVnode有children'); 
      /*遍历children
        1.Diff比较策略,比较当前当前层次的虚拟节点,移动节点位置
          a.新前 === 旧前
          b.新后 === 旧后
          c.新后 === 旧前
          d.新前 === 旧后
          循环
        2.然后判断节点的children(children.children),递归patchVnode
      */ 
      


    }else{
      // newVnode 有children,oldVnode没有children
      // 第一步:清空oldVnode的text
      oldVode.removeChild(oldVode.elm);
      // 第二步:oldVnode追加 newVnode.children
      for(let i = 0;i<newVonde.children.length;i++){
        let newD = createElement(newVonde.children[i]);
        oldVode.appendChild(newD);
      }
      oldVode.removeChild(oldVode.elm);             
    }

  }
}

二、Diff算法策略

  • 1.Diff比较策略,比较当前当前层次的虚拟节点,移动节点位置
    • a.新前 === 旧前
    • b.新后 === 旧后
    • c.新后 === 旧前
    • d.新前 === 旧后
    • 循环
  • 2.然后判断节点的children(children.children),递归patchVnode
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值