关于vue.js:手写Vue的diff算法

42次阅读

共计 3359 个字符,预计需要花费 9 分钟才能阅读完成。


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

正文完
 0