<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
let oldVnode = {
value: 0,
children: [
{
value: 1,
children: [
{
value: 1,
elm: []},
{
value: 2,
elm: []},
],
elm: [1, 2]
},
{
value: 2,
children: [
{
value: 1,
elm: []}
],
elm: [1]
},
{
value: 3,
children: [],
elm: []}
],
elm: [1, 2, 3]
}
let vnode = {
value: 0,
children: [
{
value: 2,
children: [{ value: 3} ],
},
{
value: 3,
children: [{ value: 1}, {value: 2} ],
},
{
value: 5,
children: [{ value: 1}, {value: 2}, {value: 3}],
}
],
}
console.log(patch( oldVnode, vnode) )
function patch(oldVnode, vnode) {sameVnode( oldVnode, vnode) ?
patchVnode(oldVnode, vnode) : createElm(vnode)
return vnode
}
function createElm(vnode) {let elm = vnode.elm = []
const children = vnode.children || []
for(let i =0 ; i < children.length; i++) {let child = children[i]
createElm(child)
elm.push(child.value)
}
}
function sameVnode(oldVnode, vnode) {return oldVnode.value === vnode.value}
function patchVnode(oldVnode, vnode) {
let oldChildren = oldVnode.children && oldVnode.children.length
let children = vnode.children && vnode.children.length
if (oldChildren && children) {updateChildren(oldVnode.elm, oldVnode.children, vnode.children)
vnode.elm = oldVnode.elm
}else if (oldChildren) {vnode.elm = []
}else if (children) {createElm( vnode)
}
}
function updateChildren(oldElm, oldChildren, children) {
let newStartIndex = 0
let newStart = children[newStartIndex]
let oldStartIndex = 0
let oldStart = oldChildren[oldStartIndex]
let newEndIndex = children.length - 1
let newEnd = children[newEndIndex]
let oldEndIndex = oldChildren.length - 1
let oldEnd = oldChildren[oldEndIndex]
while(oldStartIndex <= oldEndIndex && newStartIndex <= newEndIndex) {if ( !oldStart) {oldStart = oldChildren[ ++oldStartIndex]
}else if (!oldEnd) {oldEnd = oldChildren[ --oldEndIndex]
}else if (sameVnode( oldStart, newStart) ) {patchVnode( oldStart, newStart)
oldStart = oldChildren[++oldStartIndex]
newStart = children[++newStartIndex]
}else if (sameVnode( oldEnd, newEnd) ) {patchVnode( oldEnd, newEnd)
oldEnd = oldChildren[--oldEndIndex]
newEnd = children[--newEndIndex]
}else if (sameVnode( oldStart, newEnd) ) {patchVnode( oldStart, newEnd)
moveArray(oldElm, oldStart.value, oldEnd.value, false)
oldStart = oldChildren[++oldStartIndex]
newEnd = children[--newEndIndex]
}else if (sameVnode( oldEnd, newStart) ) {patchVnode( oldEnd, newStart)
moveArray(oldElm, oldEnd.value, oldStart.value, true)
oldEnd = oldChildren[--oldEndIndex]
newStart = children[++newStartIndex]
}else {
let startIndex = oldStartIndex
while(startIndex <= oldEndIndex) {let oldNode = oldChildren[ startIndex]
if (sameVnode( oldNode, newStart) ) {patchVnode( oldNode, newStart)
oldChildren[startIndex] = undefined
moveArray(oldElm, oldNode.value, oldStart.value, true)
break
}
startIndex++
}
if (startIndex > oldEndIndex) {createElm( newStart)
oldElm.splice(oldElm.indexOf( oldStart), 0, newStart.value )
}
newStart = children[++newStartIndex]
}
}
if (oldStartIndex > oldEndIndex) {for(; newStartIndex <= newEndIndex ;) {newStart = children[ newStartIndex++]
createElm(newStart)
children[newEndIndex + 1] ?
oldElm.splice(oldElm.indexOf( children[ newEndIndex + 1].value ), 0, newStart.value ) :
oldElm.push(newStart.value)
}
}else {for( ; oldStartIndex <= oldEndIndex ;) {oldStart = oldChildren[ oldStartIndex++]
oldStart && oldElm.splice(oldElm.indexOf( oldStart), 1 )
}
}
}
function moveArray(array, source, target, forward) {const sourceIndex = array.indexOf( source)
const targetIndex = array.indexOf(target)
let [targetItem] = array.splice(sourceIndex, 1)
array.splice(targetIndex + ( forward ? 0 : 1), 0, targetItem )
}
</script>
</body>
</html>