虚拟DOM之Snabbdom的使用

    技术2022-07-11  93

    Snabbdom是一个虚拟DOM库。 

    parcel是一个打包工具,使用非常简单,0配置。

    创建Snabbdom项目结构的基本步骤:

    //创建项目目录 md snabbdom-demo //进入项目 cd snabbdome-demo //创建package.json npm init或yarn init -y //本地安装parcel-bundler npm install parcel-bundler或yarn add parcel-bundler //在package.json文件中,script项配置启动命令和打包命令 "script":{ "dev":"parcel index.html --open",//如果要浏览器自动打开的话就加上--open "build":"parcel build index.html"//index.html是入口文件 }

    开始写项目的基本步骤:

    //安装snabbdom npm install snabbdom --save或yarn add snabbdom //注意新版本似乎有问题,引入以后报错,所以安装的时候可以安装0.7版本的 npm install snabbdom@0.7.0 //引入snabbdom import {h,thunk,init} from "snabbdom"; //注意snabbdom是使用export导出的,所以没办法不写{},而且看源码,它一共导出了三个方法。 //不过使用requie的方式导入的话,可以写成const snabbdom=require("snabbdom"),至于为什么require可以,具体见ES6和CommonJS模块化的差异

    init()是一个高阶函数,返回patch()。

    h()返回虚拟节点VNode。(vue的render里面有使用到这个方法哦)

    thunk()一种优化策略,可在处理不可变数据时使用。

    具体使用:

    import { h, thunk, init } from "snabbdom"; //patch方法比较两个vnode的差异并更新到真实dom中,返回值是虚拟dom。第一个参数可以是DOM元素,内部会把DOM元素转换成vnode const patch=init([]); let vnode=h("div#box.box","hello"); const app=document.querySelector("#app"); const oldVnode=patch(app,vnode); //至此,重新运行,页面中的<div id="app"></div>将会被替换成<div id="box" class="box">hello</div> console.log(oldVnode) vnode=h("div.box","hello snabbdom"); patch(oldVnode,vnode); //至此,重新运行,页面中的<div id="box" class="box">hello</div>将会被替换成<div class="box">hello snabbdom</div>

    div中加子元素,h函数的第二个参数将会是一个数组

    import {h, thunk,init} from "snabbdom"; const patch=init([]); const app=document.querySelector("#app"); let vnode=h("div#box",[ h("h1","我是标题"), h("p","我是段落") ]); const oldVnode=patch(app,vnode); //两秒钟中内容发生变化 setTime(()=>{ vnode=h("div#box",[ h("h1","标题"), h("p","段落") ]); patch(oldVnode,vnode); //清空页面元素可以利用注释节点 patch(oldVnode,h("!")) },2000)

    snabbdom模块的使用:

    导入模块,注册模块,使用h函数的第二个参数传入模块需要的数据

    import { h, thunk, init } from "snabbdom"; //引入模块 import styles from "snabbdom/modules/style"; import eventlisteners from "snabbdom/modules/eventlisteners"; //注册模块 const patch=init([styles,eventlisteners]); const app=document.querySelector("#app"); //引入模块时,第二个参数是对象,如果没有子元素,第三个参数就是字符串,有子元素就是数组 let vnode=h("div",{ style:{ backgroundColor:"blue" }, on:{ click:eventHandle } },[ h("h1","我来测试标题") ]); function eventHandle(){ console.log('点击事件') } patch(app,vnode);//运行以后页面上就会立马显示出来,感觉#app这个元素有点像一开始用来占位置的

    源码解读:

    主要是解读h.ts、snabbdom.ts、vnode.ts文件。

    了解函数重载的概念。(js里面没有函数重载,ts里面是有的)

    h函数核心就是调用vnode返回一个虚拟节点。

    vnode:每个vnode都有的属性,sel选择器;data节点数据,属性/样式/事件等;children子节点,与text互斥;elm记录vnode对应的真实DOM;text节点中的内容,与children互斥;key优化用。

    snabbdom:vnode如何创建真实节点。

    patch(oldVnode,newVnode):打补丁,把新节点中变化的内容渲染到真实DOM中,最后返回新节点作为下一次处理的节点;对比新旧Vnode是否相同节点(节点的key和sel相同);如果不是相同节点,删除之前的内容,重新渲染;是相同节点,再判断新的Vnode是否有text,如果有并且和oldVnode的text不同,直接更新文本内容;如果新的Vnode有children,判断子节点是否有变化,判断子节点过程中使用的diff算法;diff算法过程只进行同层级比较。

    Processed: 0.011, SQL: 9