最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 原生js实现DOM与虚拟DOM相互转化

    正文概述 掘金(上头小官)   2021-03-28   681

    前言

    认认真真学习vue源码,从0到1。。。

    像Vue、React 这样的框架,对于其模板转换成虚拟DOM,再进行后续操作的用法应该耳熟能详,那么怎么实现一个DOM和虚拟DOM的相互转换呢? 这里我用的是递归的方式简单的做转化,与Vue、React底层实现的方式不同,只是为了更好的了解DOM和虚拟DOM。

    首先要了解为什么需要虚拟DOM?

    由于在我们日常开发中,经常需要修改DOM,频繁操作真实DOM会触发重绘和重排,严重影响页面性能,所以提出了虚拟DOM,作为真实DOM的抽象,以对象的形式存储DOM信息,缓存在内存中,一次性更新真实DOM,提高性能。

    准备知识

    1. DOM是什么?

    详细的DOM原生API可以参考MDN:DOM

    DOM是 JavaScript 操作网页的接口,全称为“文档对象模型”, DOM模型用一个逻辑树来表示一个文档,树的每个分支的终点都是一个节点(node),每个节点都包含着对象(objects)。

    节点(node)是DOM树的最小单位,文档的树形结构就是有各个不同列类型(Document、Element、Text)的节点组成的。

    详细的NODE原生API参考MDN:NODE

    在一个html文件中写一段简单的DOM结构
    
    <div id="root" class="c1">
        <p>你好</p>
    </div>
    <script>
      const root = document.querySelector('#root')
      console.dir(root)
      console.dir(root.childNodes)
    </script>
    

    在控制台打印出DOM结构

    原生js实现DOM与虚拟DOM相互转化

    2. NODE的属性

    1. nodeName:node的名字,如果是element那名字是大写的,其他的名字前面写上#。

    2. nodeType:node的类型,一般用数字表示,1表示element(也可以用Node.ELEMENT_NODE来表示),3表示text(Node.TEXT_NODE)。

      如果是element,那么nodeName === tagName

      如果是text,那么nodeName = #text, tagName = undefined

    3. nodeValue:当前节点的值,对于text, comment节点来说, nodeValue返回该节点的文本内容,对于 attribute 节点来说, 返回该属性的属性值,而对于document和element节点来说,返回null

    原生js实现DOM与虚拟DOM相互转化

    真实DOM => 虚拟Dom

    // 创建VDom类
    class VDom {
        constructor(tag, data, value, type) {
          this.tag = tag && tag.toLowerCase() // 节点名
          this.data = data // 属性
          this.value = value // 文本数据
          this.type = type // 节点类型
          this.children = []
        }
        appendChild(vnode) {
          this.children.push(vnode)
        }
      }
    
      function getVNode(node) {
        let nodeType = node.nodeType
        let _vnode = null
        if (nodeType === 1) {
          // 元素
          let tag = node.nodeName
          let attrs = node.attributes
          let _attrObj = {}
          for (let i = 0; i< attrs.length; i++) {
            _attrObj[attrs[i].nodeName] = attrs[i].nodeValue
          }
          _vnode = new VDom(tag, _attrObj, undefined, nodeType)
          
          let children = node.childNodes
          for (let i = 0; i < children.length; i++) {
            _vnode.appendChild(getVNode(children[i]))
          }
        } else if (nodeType === 3) {
          // 文本
          _vnode = new VDom(node.nodeName, undefined, node.nodeValue, nodeType)
        }
        return _vnode
      }
      const vroot = getVNode(document.querySelector('#root'))
      console.log(vroot)
    

    最终转换的VDom格式如下:

    原生js实现DOM与虚拟DOM相互转化

    虚拟DOM => 真实DOM

    这里有一个知识点,如果通过一个nodeName创建一个元素节点?

    如何通过一段文本创建一个文本节点?

    createElement: 通过指定名称创建一个元素

    createTextNode:创建文本节点

    function parseVNode(vnode) {
        let type = vnode.type
        let rdom = null
        if (type === 1) {
          rdom = document.createElement(vnode.tag)
          // 元素
          let attrs = vnode.data
          for (let key in attrs) {
            rdom.setAttribute(key, attrs[key])
          }
          let children = vnode.children
          for (let i = 0; i < children.length; i++) {
            rdom.appendChild(parseVNode(children[i]))
          }
        } else if (type === 3) {
          // 文本
          rdom = document.createTextNode(vnode.value)
        }
        return rdom
    }
    const realRoot = parseVNode(vroot)
    console.log(realRoot)
    document.body.appendChild(realRoot)
    

    原生js实现DOM与虚拟DOM相互转化

    总结

    本文主要是用递归的方式,用原生js实现真实DOM和虚拟DOM直接的转化,是很基础的知识点,现在很多人用框架久了不会使用原生方法了,做这些小练习对于了解原生js和阅读框架源码都有好处。

    文章如有错误请大家及时指出,莫怪莫怪!

    二话不多说,滚去继续学习啦~~~

    原生js实现DOM与虚拟DOM相互转化


    起源地下载网 » 原生js实现DOM与虚拟DOM相互转化

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元