服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

node.js|vue.js|jquery|angularjs|React|json|js教程|

服务器之家 - 编程语言 - JavaScript - React - react中的虚拟dom和diff算法详解

react中的虚拟dom和diff算法详解

2022-03-05 20:49家里有只猪 React

这篇文章主要介绍了react中的虚拟dom和diff算法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

虚拟DOM的作用

首先我们要知道虚拟dom的出现是为了解决什么问题的,他解决我们平时频繁的直接操作DOM效率低下的问题。那么为什么我们直接操作DOM效率会低下呢?

比如我们创建一个div,我们可以在控制台查看一下这个div上自带或者继承了很多属性,尤其是我们使用js操作DOM的时候,我们的DOM本身就很复杂,js的操作也会占用很多时间,但是我们控制不了DOM元素本身,因此虚拟DOM解决的是js操作DOM这一层面其实解决的是减少了操作dom的次数

简单实现虚拟DOM

虚拟DOM,见名知意,就是假的DOM,我们真实的DOM挂载在页面上的,而我们的虚拟DOM则是在内存中的。这个就需要我们把真实的DOM抽象成一个对象放在内存中。这个对象就可以是如下类型:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
var element = {
      tagName: 'div',
      props: {
        class: 'box'
      },
      children: {
        {
          tagName: 'p',
          props: {
            class: 'p1'
          },
          children: ['我是p1']
        },
         {
          tagName: 'p',
          props: {
            class: 'p2'
          },
          children: ['我是p2']
        },
        {
          tagName: 'p',
          props: {
            class: 'p3'
          },
          children: ['我是p3']
        },
      }
    }

我们想要构造出这样的对象可以自己封装一个构造函数如下:

?
1
2
3
4
5
function Element(tagName, props, children) {
    this.tagName = tagName
    this.props = props
    this.children = children
}

有了这个对象,我们需要把这个虚拟DOM渲染到真实DOM上,可以写出如下方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Element.prototype.render = function () {
    const { tagName, props, children } = this
    var el = document.createElement(tagName)
    for (key in props) {
        el.setAttribute(key, props[key])
    }
    children.forEach((item) => {
        const childEl = (item instanceof Element) ?
              item.render() :
        document.createTextNode(item)
        el.appendChild(childEl)
    })
    return el
}

最后我们可以new出这个对象调用render()方法然后appendChild到body中就好了:

?
1
2
3
4
5
6
7
8
let virtualDom = new Element('div', { class: 'box' }, [
    new Element('p', { class: 'p1' }, ['我是p1']),
    new Element('p', { class: 'p2' }, ['我是p2']),
    new Element('p', { class: 'p3' }, ['我是p3']),
])
 
let a = virtualDom.render()
document.body.appendChild(a)

diff算法

首先我们先了解一下diff算法的作用

如果我们的虚拟dom发生了变化,我们的内存中又会产生新的虚拟DOM,如果我们直接用这个新的虚拟DOM结构的话,又会导致很多重复的渲染,因此 这个时候diff算法的作用就体现了出来,diff通过比较新旧两个虚拟DOM树,找出差异,并且记录下来,然后把记录的差异应用到真实的DOM树上。

原理:

diff算法通过对新旧两颗树进行深度优先遍历,每一个节点都加一个唯一的标识。

这个过程分为2步

  • 找出两个树的差异,并记录在一个伪数组里。
  • 把这些不同应用到真实的DOM树上

对于dom的操作基本可化为4种类型

  • 对节点的删除,移动,添加子节点
  • 更换节点标签
  • 对于文本节点,修改节点文本
  • 修改节点props

下面会用伪代码的形式大致过一下这个流程

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
// diff 函数,对比两棵树
function diff(oldTree, newTree) {
    var patchs = {};  // 伪数组,记录差异
    //  对4种节点做错判断
    dfWork(oldTree, newTree, patchs, index)
 
    return patchs
 
}
function dfWork(oldTree, newTree, patchs, index) {
    let currentPatch = []
 
    if (1) { // 对节点的删除
        currentPatch.push()
    } else if (3) { // 对节点的文本的更换
        currentPatch.push()
 
    } else { // 修改节点的props 对children的检查
        // 对props作diff算法,把变化记录到patchs中。
        currentPatch.push({ type: patch.PROPS, props: propsPatches })
        // 然后需要对子节点作diff算法
        diffChildren(oldNode.children, newNode.children, index, patches, currentPatch)
    }
}
function diffChildren(oldChildren, newChildren, index, patches, currentPatch) {
 
    // 对子节点作diff算法,遍历子节点,递归调用dfWork,做差异得到patchs
 
}
// 把变化应用在真实的DOM树上
function patch(node, patchs) {
    // node为老的DOM树,patchs变化。
    // 我们会遍历这个patchs,并且把node和patch对应上,
}
function applyPatch(node, patchs) {
    // 应为每个节点可能有多个变化,所以也需要遍历
    switch (patchs.type) {
        case REPLACE: // 节点替换
            // node.render()
            break;
        case REORDER:  // 节点的移动删除新增子节点。
 
            break;
        case PROPS:
            // setProps
            break;
        case TEXT: // 对节点文本的修改
            // node.nodeValue
            break;
 
        default:
            break;
    }
}

参考文档:深度剖析:如何实现一个 Virtual DOM 算法 作者:livoras,内置源码。

到此这篇关于react中的虚拟dom和diff算法的文章就介绍到这了,更多相关react虚拟dom和diff算法内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://blog.csdn.net/qq_44983621/article/details/115733067

延伸 · 阅读

精彩推荐
  • Reactreact如何用懒加载减少首屏加载时间

    react如何用懒加载减少首屏加载时间

    这篇文章主要介绍了react如何利用懒加载减少首屏加载时间,帮助大家更好的理解和学习使用react,感兴趣的朋友可以了解下...

    阿政想暴富7412022-03-03
  • React深入理解React Native核心原理(React Native的桥接(Bridge)

    深入理解React Native核心原理(React Native的桥接(Bridge)

    这篇文章主要介绍了深入理解React Native核心原理(React Native的桥接(Bridge),本文重点给大家介绍React Native的基础知识及实现原理,需要的朋友可以参考下...

    Gavell9712022-02-23
  • ReactReact tsx生成随机验证码

    React tsx生成随机验证码

    这篇文章主要为大家详细介绍了React tsx生成随机验证码,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    laipengfei196252022-03-09
  • Reactreact获取input输入框的值的方法示例

    react获取input输入框的值的方法示例

    这篇文章主要介绍了react获取input输入框的值的方法示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友...

    Pinkh8222022-02-24
  • Reactreact diff算法源码解析

    react diff算法源码解析

    这篇文章主要介绍了react diff算法源码解析的相关资料,帮助大家更好的理解和学习使用react,感兴趣的朋友可以了解下...

    zhangyu5632022-02-27
  • Reactreact-native 实现购物车滑动删除效果的示例代码

    react-native 实现购物车滑动删除效果的示例代码

    这篇文章主要介绍了react-native 实现购物车滑动删除效果的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,...

    程序猿tx3902021-12-31
  • React详解React Fiber的工作原理

    详解React Fiber的工作原理

    这篇文章主要介绍了React Fiber的工作原理的相关资料,帮助大家更好的理解和学习使用React框架,感兴趣的朋友可以了解下...

    陌上兮月7942022-03-08
  • ReactReact html中使用react的两种方式

    React html中使用react的两种方式

    这篇文章主要介绍了React html中使用react的两种方式,本文给大家提到了React pwa的配置代码,给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴...

    愚公搬代码6422022-02-23