diff算法
snabbdom:
h函数:产生虚拟节点
第一个参数:为标签,第二个:属性 ,第三个:值
一个虚拟dom的属性:让虚拟节点上树,即生成真实dom
//h函数
//vnode:把参数返回成一个对象
export default function(sel,data,children,text,elm){
const key=data.key
return {sel,data,children,text,elm}
}
import vnode from './vnode.js'
//低配版本的diff,必须接受三个参数
// h('div',{},'文字'/[]/h{})
export default function h(a,b,c){
if(arguments.length<3){
return ;
}
if(typeof c =='string'||typeof c=='number'){
return vnode(a,b,undefined,c,undefined)
}
if(Array.isArray(c)){
let children=[]
for(let i=0;i<c.length;i++){
if(!(typeof c[i]=='object'&& c[i].hasOwnProperty(sel))){
return
}
children.push(c[i])
}
return vnode(a,b,children,undefined,undefined)
}
if(typeof c=='object' &&c.hasOwnProperty(sel)){
let children=[c]
return vnode(a,b,children,undefined,undefined)
}else{
return
}
}
h('div',{},'文字')
diff算法:
//patch函数:
过程:
先判断老节点是否为虚拟节点,若不是,把它转化为虚拟节点,若是,则判断旧vnode和新的vnode是否为同一节点,若是进行精细比较,若不是,则直接暴力删除添加
(1):如何定义 是相同节点:
新旧节点的key相同和新旧节点的选择器相同
(2):暴力删除旧的,插入新节点
创建子节点时,递归创建
const myvnode1=h('h1',{},'你好')
const container=document.getElementById('container')
function patch(oldvnode,newnode){
if(oldnode.sel==''||oldnode.sel=='undefioned'){
oldvonde=vnode(oldvnode.tagname.toLowerCase(),{},[],undefined,oldvnode)
}
if(oldvnode.key==newvnode.key&&oldvnode.sel===newvnode.sel){
//判断新旧是否为一个对象
patchVnode(oldVnode,newvnode)
}else{
let newdom=createElement(newvnode)
//插入
oldVonde.elm.parentNode.insertBefore(newdom,oldvnode.elm)
oldvnode.ele.parentNode.removeChild(oldvnode);
}
}
function patchvnode(oldvnode,newvnode){
if(oldvnode==newvnode) return
if(newvnode.text!=='undefined' &&newvnode.children.length==0){
if(newvnode.text!=oldvnode.text){
oldvnode.elm.innerText=newvnode.text
}
}else{
//判断老的有没有children
if(oldvnode.children!=='undefined'&&oldvnode.children.length!==0){
updateChilden(oldvnode.elm,oldvnode.children,newvnode.children)
}else{
//老的没有,新的有
oldvnode.elm.innerHTML=''
for(let i=0;i<newvnode.chileren.length;i++){
let dom=createElement(newvnode.children[i])
oldvnode.ele.appChildren(dom)
}
}
}
}
function createElement(vnode){
//创建dom
let domnode=document.createElement(vnode.sel)
if(vnode.text!=''&&(vnode,children=='undefined)){
domNode.innerText=vnode.text;
}else if(Array.isArray(vnode.children)&&vnode.children.length>0){
//内部是子节点,要进行递归
for(let i=0;i<vnode.children.length;i++){
let ch=vnode.childrfen[i]
let chdom=createElement(ch)
domnode.appendChild(chdom)
}
}
vnode.elm=domnode
return vnode.elm
}
function updateChilden(parentelm,oldch,newch){
let oldstart=0;
let newstart=0;
let oldend=oldch.length-1;
let newend=newch.length-1;
let oldsnode=oldch[0]
let oldenode=old[oldend]
let newsnode=newch[0]
let newenode=newch[newend]
while(oldstart<=oldend&&newstart<=newend){
if(checksamenode(oldsnode,newsnode)){
patchvnode(oldsnode,newsnode)
oldsnode=oldch[++oldstart]
newsnode=newch[++newstart]
}
//新后和旧后
else if(checksamenode(oldenode,newenode)){
patchvnode(oldenode,newenode)
oldenode=oldch[--oldend]
newenode=newch[--newend]
}else if(checksamenode(oldsnode,newenode)){
patchvnode(oldsnode,newenode)
parentelm.insertBefore(oldsnode.elm,oldenode.elm.nextSibling)
oldsnode=oldch[++oldstart]
newenode=newch[--newend]
}else if(checksamenode(oldenode,newsnode)){
patchvnode(oldenode,newsnode)
parentelm.insertBefore(oldenode.elm,oldsnode.elm)
oldenode=[--oldend]
newsnode=[++newstart]
}else{
}
}
//
剩余节点
if(newstart<=newend){
for(let i=newstart,i<=newend;i++){
parentelm.insertBefore(createElement(newch[i]),newch[i+1].elm)
}
}else if(oldstart<oldend){
for(let i=oldsrart,i<=oldend;i++){
parentelm.removeChild(oldch[i])
}
}
}
function checksamenode(a,b){
return a.sel==b.sel&&a.key==b.key
}
diff算法优化:
虚拟dom变为真实dom