请使用js实现vue的diff算法

function diff(oldVnode, newVnode) {
  if (!oldVnode) {
    return createVnode(newVnode); // 新增节点
  }

  if (!newVnode) {
    return destroyVnode(oldVnode); // 删除节点
  }

  if (isSameVnode(oldVnode, newVnode)) {
    patchVnode(oldVnode, newVnode); // 更新节点
  } else {
    replaceVnode(oldVnode, newVnode); // 替换节点
  }
}


function isSameVnode(oldVnode, newVnode) {
  return oldVnode.key === newVnode.key && oldVnode.tag === newVnode.tag;
}


function createVnode(vnode) {
  // 创建真实DOM并插入到文档中
  const el = document.createElement(vnode.tag);
  if (vnode.text) {
    el.textContent = vnode.text;
  } else if (vnode.children) {
    vnode.children.forEach(child => {
      el.appendChild(createVnode(child));
    });
  }
  vnode.el = el; // 将真实DOM挂载到vnode上
  return el;
}


function destroyVnode(vnode) {
  if (vnode.el) {
    vnode.el.parentNode.removeChild(vnode.el);
  }
}


function patchVnode(oldVnode, newVnode) {
  newVnode.el = oldVnode.el; // 复用DOM元素

  // 更新文本节点
  if (newVnode.text !== undefined && newVnode.text !== oldVnode.text) {
    oldVnode.el.textContent = newVnode.text;
  }

  // 更新子节点
  if (oldVnode.children && newVnode.children) {
    updateChildren(oldVnode.el, oldVnode.children, newVnode.children);
  } else if (newVnode.children) { // 老节点没有子节点,新节点有子节点
    newVnode.children.forEach(child => {
      oldVnode.el.appendChild(createVnode(child));
    });
  } else if (oldVnode.children) { // 老节点有子节点,新节点没有子节点
    oldVnode.el.innerHTML = '';
  }
}

function replaceVnode(oldVnode, newVnode) {
    const newEl = createVnode(newVnode);
    oldVnode.el.parentNode.replaceChild(newEl, oldVnode.el);
    destroyVnode(oldVnode);
}



function updateChildren(parentElm, oldCh, newCh) {
  // 简化版,只实现了简单的头尾比较,没有实现双指针算法
  let oldStartIdx = 0;
  let newStartIdx = 0;
  let oldEndIdx = oldCh.length - 1;
  let newEndIdx = newCh.length - 1;


  while (oldStartIdx <= oldEndIdx && newStartIdx <= newEndIdx) {
    if (isSameVnode(oldCh[oldStartIdx], newCh[newStartIdx])) {
      patchVnode(oldCh[oldStartIdx], newCh[newStartIdx]);
      oldStartIdx++;
      newStartIdx++;
    } else if (isSameVnode(oldCh[oldEndIdx], newCh[newEndIdx])) {
      patchVnode(oldCh[oldEndIdx], newCh[newEndIdx]);
      oldEndIdx--;
      newEndIdx--;
    } else {
      // 其他情况,为了简化,直接替换
      replaceVnode(oldCh[oldStartIdx], newCh[newStartIdx]);
      oldStartIdx++;
      newStartIdx++;
    }
  }

  // 添加新节点
  if (newStartIdx <= newEndIdx) {
    for (let i = newStartIdx; i <= newEndIdx; i++) {
      parentElm.appendChild(createVnode(newCh[i]));
    }
  }

  // 删除老节点
  if (oldStartIdx <= oldEndIdx) {
    for (let i = oldStartIdx; i <= oldEndIdx; i++) {
      destroyVnode(oldCh[i]);
    }
  }
}


// Example usage (simplified vnode representation):
const oldVnode =
posted @ 2024-12-08 09:14  王铁柱6  阅读(16)  评论(0)    收藏  举报