<!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>
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。