认识虚拟DOM

314 阅读2分钟

认识虚拟DOM

先导语

今天我们来学习一下vue的虚拟DOM。

什么是虚拟DOM

虚拟DOM(vdom):虚拟DOM就是用js来模拟DOM结构,计算出最小的变更,然后再进行DOM操作
我们来看一下下面这段DOM结构用js怎么模拟呢?

image.png
使用js模拟的DOM结构:

image.png

snabbdom

snabbdom是一个强大的vdom的库,vue2就是参考它来实现vdom。
github地址:github.com/snabbdom/sn…
接下来我们就就用这个库来写一个demo来看看vdom的效果:
html代码:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <div id="container"></div>
    <button id="btn-change">change</button>

    <!-- 引入snabbdom-->
    <script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom.js"></script>
    <script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-class.js"></script>
    <script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-props.js"></script>
    <script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-style.js"></script>
    <script src="https://cdn.bootcss.com/snabbdom/0.7.3/snabbdom-eventlisteners.js"></script>
    <script src="https://cdn.bootcss.com/snabbdom/0.7.3/h.js"></script>
    <!--    引入demo.js-->
    <script src="./demo1.js"></script>
</body>
</html>

js代码:

const snabbdom = window.snabbdom

// 定义 patch
const patch = snabbdom.init([
    snabbdom_class,
    snabbdom_props,
    snabbdom_style,
    snabbdom_eventlisteners
])

// 定义 h
const h = snabbdom.h

const container = document.getElementById('container')

// 生成 vnode
const vnode = h('ul#list', {}, [
    h('li.item', {}, 'Item 1'),
    h('li.item', {}, 'Item 2')
])
patch(container, vnode)

document.getElementById('btn-change').addEventListener('click', () => {
    // 生成 newVnode
    const newVnode = h('ul#list', {}, [
        h('li.item', {}, 'Item 1'),
        h('li.item', {}, 'Item B'),
        h('li.item', {}, 'Item 3')
    ])
    patch(vnode, newVnode)

    // vnode = newVnode // patch 之后,应该用新的覆盖现有的 vnode ,否则每次 change 都是新旧对比
})

注意点:
1. 使用snabbdom提供的h函数来生成vnode结构
2. patch既可以往一个dom中渲染vdom结构,也可以更新vdom结构
代码运行结果:

20211117_211028 (online-video-cutter.gif

从结果上,我们可以看到:每次改变只有需要改变的dom节点重新渲染了,其他的dom节点并没有重新渲染
为了更明显的对比,我们再看一个没有使用vdom的demo,看看在没有使用虚拟dom时,dom节点是如何进行更新的。 代码如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <div id="container"></div>
    <button id="btn-change">change</button>

    <script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.2.0/jquery.js"></script>
    <script type="text/javascript">
        const data = [
            {
                name: '张三',
                age: '20',
                address: '北京'
            },
            {
                name: '李四',
                age: '21',
                address: '上海'
            },
            {
                name: '王五',
                age: '22',
                address: '广州'
            }
        ]

        // 渲染函数
        function render(data) {
            const $container = $('#container')

            // 清空容器,重要!!!
            $container.html('')

            // 拼接 table
            const $table = $('<table>')

            $table.append($('<tr><td>name</td><td>age</td><td>address</td>/tr>'))
            data.forEach(item => {
                $table.append($('<tr><td>' + item.name + '</td><td>' + item.age + '</td><td>' + item.address + '</td>/tr>'))
            })

            // 渲染到页面
            $container.append($table)
        }

        $('#btn-change').click(() => {
            data[1].age = 30
            data[2].address = '深圳'
            // re-render  再次渲染
            render(data)
        })

        // 页面加载完立刻执行(初次渲染)
        render(data)

    </script>
</body>
</html>

结果:

20211117_212858 (online-video-cutter.gif 我们可以看出,没有使用vdom的整个table表格都重新渲染了。

注意点

vue3重写了vdom的部分,但是关于vdom部分的基本理念是不变的

结束语

今天,我们主要理解了什么是虚拟dom,并通过snabbdom库来对比了下使用vdom和不使用vdom的区别。通过今天的学习,让我对vdom的理解更加深刻。那么,下次见。好好学习,天天向上!

image.png