源码学习——snabbdom(一)

836 阅读3分钟

前言

前端同学应该都听过虚拟dom,不管是vue还是react源码中都用了虚拟dom这一概念。如果我们想要提升自己掌握一下虚拟dom的实现原理不用费劲地去看vue、react源码,直接查看虚拟dom库——snabbdom即可。本节开始我们就来学习一下snabbdom的源码,彻底搞清楚虚拟dom的实现过程。

snabbdom

snabbdom是一个精简化的虚拟dom库,它的核心代码只能200多行,用法也很简单:

import {
  init,
  classModule,
  h
} from "snabbdom";
// 初始化
const patch = init([classModule]);
//获取dom元素
const app = document.getElementById("app");
//生成dom
const vnode = h("span",{},"这是虚拟dom");
// 更新dom
patch(app, vnode);

上面的代码是不是很熟悉,vue中都类似的写法。在我们初始化的时候我们可以根据需要添加不同的 module来丰富功能,感兴趣的可以自己多尝试下。下面我们直接学习源码,首先来学习一下init方法。

init

打开snabbdom源码,找到init.ts文件,里面的源码不少,我们先抛除其他功能化繁为简,先梳理清楚最简单的功能。源码中export了一个init函数: image.png
该函数有三个参数:

  • modules:功能模块,必传参数。snabbdom自带了几个module,上面的例子calssModule就是样式相关的。该参数的ts类型为:

1719477529512.png
pre、create其实就是生命周期,简单来说这些modules就是在组件创建过程中添加所需的功能。

  • domApi:操作dom元素的方法,非必传,默认为DOMAPI。在保留了原生操作dom的方法基础上扩充了一些方法,比如isText、isElement等。
  • options:配置项,非必传,该参数跟fragments功能相关。
    了解完参数,我们直接看返回值,init函数返回的是patch函数,该函数就是用于更新dom,接受两个参数,第一个为dom元素或旧的虚拟dom,第二个为新的虚拟dom。 image.png
  • oldVnode、vnode接收的两个参数,上面我们已经提到了,注意第一个参数的ts类型。函数内首先定义了所需参数,然后依次执行cbs里的pre函数,cbs也就是hooks。 1719828020094.png
  • isElement判断元素,这里跟fragment功能有关。isElement就是domApi中的方法
function isElement(node: Node): node is Element {
return node.nodeType === 1;
}
  • sanmeVnode判断两个节点是否一样,一致的话直接执行patchVnode;当不一致的时候先获取oldVnode的绑定的节点,通过该节点拿到父级节点。
  • createElm将新的vnode变成dom元素,先用domApi中的insertBefore添加新的dom元素,然后通过removeVnodes将旧的元素移出。
  • 循环insertedVnodeQueue插入队列,依次执行节点中的insert函数;最后执行hook中的post函数。
    上面我们提到过hooks就是生命周期,patch函数就像vue页面一样,按顺序执行hooks,在过程中完成虚拟dom的更新。

总结

以上就是snabbdom中核心方法init及返回函数的解析,这里我们简略梳理了init的过程,整个过程还是简单明了的。