以面向对象的设计方式,实现一个简单的虚拟dom

文章介绍了虚拟DOM作为优化网页性能的技术,它是一个轻量级的对象,存储页面元素信息,用于减少对真实DOM的操作。通过创建和渲染虚拟DOM对象的示例代码,展示了如何使用JavaScript实现这一过程,以提高应用的效率。
摘要由CSDN通过智能技术生成

什么是虚拟dom

真实dom大家应该都知道,就是html的文档对象呗,文档中的每个元素都对应一个真实dom对象,通过操作真实dom对象,我们可以获取、修改、添加和删除HTML元素。

那么问题来了,什么是虚拟dom?在我看来,虚拟dom就是存储页面元素信息的一个对象,它和真实dom一样都存储了元素的内容、元素的属性、元素之间的结构等信息。但不同的是,虚拟dom的属性更加精简,而且虚拟dom不能直接渲染,需要转化成真实dom才能渲染。

如下图所示,我在控制台打印了一个div元素的真实dom,可以看到这个对象有着非常多的属性。操作一个如此庞大的对象,代价是昂贵的。尤其是数据频繁变动的时候,每次数据变动都要去修改dom,很有可能会引起性能问题。但如果引进虚拟dom的话,数据发生变动时,我们先去修改虚拟dom,由于虚拟dom对象的体量很小,操作速度很快,短时间内多次修改也不会有太大的性能问题,最终将多次修改的结果一次性地同步到真实dom上,这样就只需要操作一次真实dom,性能大大优化。
在这里插入图片描述

虚拟dom的实现

下面我将实现一个简单虚拟dom对象的创建和渲染。

下面代码中的Vdom类,就是我所定义的虚拟dom类,类里面有三个属性tagName、attrs、children,它们的含义分别是标签名、标签属性、子元素。

Vdom有一个成员方法render(),此方法的职责是渲染这个Vdom对象,它的返回值一个真实的dom对象。它的大致流程是这样的:

  • 如果tagName是’text’,那说明这是一个文本节点,则调用document.createTextNode()创建一个文本节点对象并返回
  • 如果tagName不是’text’,那说明这是一个html元素,则调用document.createElement()创建一个dom对象,并遍历attrs设置该dom对象的属性值。然后遍历children数组,为子元素创建Vdom对象并渲染,把子元素的真实dom对象添加进来。最后return即可。
class Vdom{
  constructor(tagName, attrs, children){
    this.tagName = tagName
    this.attrs = attrs || {}
    this.children  = children || []
  }
  render(){
    let htmlElement 
    if(this.tagName == 'text'){
      htmlElement = document.createTextNode(this.attrs['nodeValue'])
    }
    else {
      htmlElement = document.createElement(this.tagName)
      // 设置真实dom的属性
      for(let key in this.attrs){
        // 很怪,直接htmlElement.style = this.attrs['style']不起作用
        if(key === 'style'){
          for(let styleKey in this.attrs['style']){
            htmlElement.style[styleKey] = this.attrs['style'][styleKey]
          }
        }
        else {
          htmlElement[key] = this.attrs[key]
        }
      }
      // 为子元素创建真实dom,并添加到当前dom下
      for(let child of this.children){
        let childVdom = new Vdom(child.tagName, child.attrs, child.children)
        htmlElement.append(childVdom.render())
      }
    }
    return htmlElement
  }
}

最后,写代码来测试一下。

下面是我的测试代码,可以看到我调用Vdom类创建了一系列虚拟dom对象,它们之间有着多层级的嵌套和复用关系,最后我把虚拟dom转换成真实dom并添加到body元素下,在浏览器中运行的效果如图所示:

在这里插入图片描述

<!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>
  <script src="./vdom.js"></script>
  <script>
    let textVdom = new Vdom('text', {nodeValue: '你好,再见'})
    let h1Vdom = new Vdom('h1', {style: {color: 'red'}}, [textVdom])
    let liVdom = new Vdom('li', {style: {color: 'white'}}, [textVdom])
    let pVdom = new Vdom(
      'p', 
      {style: {width: '200px', height: '200px', 'background-color': 'purple'}}, 
      [h1Vdom, liVdom]
    )
    let divVdom = new Vdom(
      'div', 
      {style: {width: '320px', height: '320px', 'background-color': 'grey'}}, 
      [h1Vdom, liVdom, pVdom]
    )
    console.dir(divVdom)

    // 渲染,把虚拟dom转换成真实dom
    let htmlDivElement = divVdom.render()
    document.querySelector('body').append(htmlDivElement)
  </script>
</body>
</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值