虚拟dom与diff算法原理

954 阅读2分钟

新虚拟DOM与旧的虚拟DOM进行diff精细化比较,算出如何最小量更新,最后反应到真实DOM上;

  • key很重要,key是这个节点的唯一标识,告诉diff算法,在更改前后它们是同一节点
  • 只有是同一虚拟节点,才会进行精细化比较,否则就会暴力拆除旧的,插入新的
  • 那么问题来了,什么才叫同一虚拟节点,答:选择器相同且key相同
  • diff算法只会进行同层比较,不会进行跨层比较,即使是同一虚拟节点,但是跨层了,对不起,diff也不会进行比较,只会暴力拆除旧的,插入新的

一个虚拟节点,包含哪些属性:

{
    children:undefined,  //包含的子节点  undefined说明没有字节点
    data:{},             //该节点所包含的属性
    elm:undefined,       //对应的真实DOM节点名字   undefined说明没有上树,浏览器还不会显示
    key:undefined,       //真实DOM上的唯一值key   undefined说明没有key
    sel:"div",           //当前dom 的名字
    text:'我是一个盒子'    //该节点内的文本信息
}

里面有几个重要的函数:

着重看h函数和patch函数

import { init } form 'snabbdom/init';
import { classModule } form 'snabbdom/module/class';
import { propsModule } form 'snabbdom/module/props';
import { styleModule } form 'snabbdom/module/style';
import { eventListenersModule } form 'snabbdom/module/eventlistenersModulers';
import { h } from 'ansbbdom/h';
// 创建patch 函数   patch 函数是diff 算法核心函数
const patch = init([classModule, propsModule, styleModule, eventListenersModule]);
 
// 创建虚拟节点
//h函数中的参数:h('标签名','属性','内部的值')
const vnode1 = h{'a', {
     props: {
        href: 'https://baidu.com';
        target: '_blank'
       }
     }, '百度'}
 
// patch 函数接受两个参数: 第一个参数(dom节点);  第二个参数: (vnode) 虚拟节点
// 让虚拟节点上树
// 首先创建container 
const container = document.getElementById('container');
patch(container, vnode1)

h 函数可以嵌套使用, 从而得到虚拟DOM树

//1: 比如这样嵌套函数
h('ul',{}, [
   h('li', {}, '牛奶'),  // h 函数用于创建vnode 节点
   h('li', {}, '咖啡'),
   h('li', {}, '可乐'),
])
 
// 2: 得到这样的虚拟DOM 树
{
  "sel": "ul",
  "data": {},
  "children": {
     { se:"li", text: "牛奶" },
     { se:"li", text: "咖啡" },
     { se:"li", text: "可乐" }
  }
} 
 
// h 函数
const vnode3 = h('ul', [
   h('li', {}, '苹果'),
   h('li', '西瓜'),
   h('li', [
     h('div', [
       h('p', '11111'),
       h('p', '22222'),
     ])
   ])
  h('li', h('p', '山楂'))
])

为什么要加key

如果不加key的话,在前面加E节点时,会重新打乱,重新渲染。如果加了key,diff就会直接找到key='E'的节点,而其他的节点不会动,从而完成最小量更新. image.png