<!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>

ox1dp6ei
1 声望1 粉丝

为了生活下海做了程序员...