ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

虚拟DOM 和 diff 算法 ——— 感受 diff 算法(第一次上树)

2021-08-11 07:34:59  阅读:249  来源: 互联网

标签:DOM elm vnode 算法 oldVnode myVnode1 diff div 节点


 一、感受 diff 算法

 

 

 当父节点发生改变时,比如 ul 变为 ol ,里面的 li 不发生改变,diff 算法是会暴力删除的。

 

 

 

2. diff 算法处理新旧节点不是同一个节点时。

snabbdom 判断是否是相同的虚拟节点:

 

 

 

 创建节点时,所有子节点需要递归创建的。

二、手写第一次上树时

1. 目录结构:

 

 

// index.html
<!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> <button id='btn'>点我改变DOM</button> <div id="container"></div> <script src="/virtual/bundle.js"></script> </body> </html>
// index.js
import h from './mySnabbdom/h' import patch from './mySnabbdom/patch' // var myVnode1 = h('div', {}, 'test') // var myVnode1 = h('div', {}, []) // var myVnode1 = h('div', {}, h()) // var myVnode1 = h('div', {}, [ // h('div', {}, '菠萝'), // h('div', {}, '香蕉'), // h('div', {}, [ // h('div', {}, '火龙果'), // h('div', {}, '牛油果'), // ]), // ]) const container = document.getElementById('container'); const btn = document.getElementById('btn'); var myVnode1 = h('ul', {}, [ h('li', {}, '火龙果'), h('li', {}, [ h('div', {}, [ h('ol', {}, [ h('li', {}, '哈哈哈'), h('li', {}, '嘿嘿嘿'), h('li', {}, '呵呵呵'), ]), ]), ]), ]); patch(container, myVnode1); var myVnode2 = h('div', {}, [ h('h1', {}, '你好'), h('h2', {}, '再见'), ]); btn.onclick = function() { patch(myVnode1, myVnode2); };

 

// patch.js
import vnode from './vnode' import createElement from './createElement'; function isVnode(vnode) { return typeof(vnode.sel) !== 'undefined'; } function isSameNode(oldVnode, newVnode) { return oldVnode.key === newVnode.key && oldVnode.sel === newVnode.sel; } export default function(oldVnode, newVnode) { // 判断 oldVnode 是虚拟节点还是 DOM 节点 if (!isVnode(oldVnode)) { // oldVnode 是 container 节点,tagName 属性是大写 // 如果是 DOM 节点,就包装成虚拟节点 oldVnode = vnode(oldVnode.tagName.toLowerCase(), {}, [], undefined, oldVnode); // sel, data, children, text, elm } // 判断 oldVnode 和 newVnode 是不是同一个节点 (key和 选择器sel 相同) if (isSameNode(oldVnode, newVnode)) { console.log('是同一个节点'); } else { // 暴力插入新的,删除旧的 let newVnodeElm = createElement(newVnode, oldVnode.elm); // 插入到老节点之前 if (oldVnode.elm.parentNode && newVnodeElm) { oldVnode.elm.parentNode.insertBefore(newVnodeElm, oldVnode.elm); } // 删除老节点 oldVnode.elm.parentNode.removeChild(oldVnode.elm); } }
// createElement.js
// 真正创建节点,将 vnode 创建为 DOM, 孤儿节点,不插入 export default function createElement(vnode) { // 标杆:pivot,在标杆前面插入新节点 vnode let domNode = document.createElement(vnode.sel); // 有子节点还是文本 if (vnode.text !== '' && (vnode.children == undefined || vnode.children.length == 0)) { // 内部是文字 domNode.innerText = vnode.text; } else if (Array.isArray(vnode.children) && vnode.children.length) { vnode.children.forEach(item => { let childVnodeElm = createElement(item); domNode.appendChild(childVnodeElm); }) } vnode.elm = domNode; // 补充 elm 属性 return vnode.elm; }

2. 界面效果:

 

 

标签:DOM,elm,vnode,算法,oldVnode,myVnode1,diff,div,节点
来源: https://www.cnblogs.com/bulu08042/p/15106857.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有