Virtual Dom(虚拟DOM)

virtual dom (虚拟DOM)简称 vdom 是Vue和React的核心部分。vdom是比较独立的部分,它是用JS来模拟dom结构,dom变化的对比放在js层来做(图灵完备语言),这样可以提高重绘性能。

图灵完备语言要求能实现各种复杂逻辑,能做到判断,循环,递归,能实现无线循环无限执行,能实现任何数据算法的语言。在前端语言(html ,
css , js)中 ,只有js是图灵完备的语言,html 和 css 都不是图灵完备的语言。

用html表示一段dom:
在这里插入图片描述
用js表示一段dom:
在这里插入图片描述
vdom就是用js来模拟一段真实的dom结构
在这里插入图片描述

浏览器最最耗性能的是dom操作,dom操作是最昂贵的,现在浏览器执行js速度是非常快的,所以vdom是很有价值的。

写个小栗子:

<!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">
        var data = [
            {
                name: '张三',
                age: '20',
                address: '北京'
            },
            {
                name: '李四',
                age: '21',//改变值为30
                address: '上海'
            },
            {
                name: '王五',
                age: '22',
                address: '广州'//改变值为深圳
            }
        ]

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

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

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

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

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

        //操作完后在控制台中整个table标签会闪烁,说明整个table表被改动了,它里面的标签重新被渲染了一遍
        $('#btn-change').click(function () {
            data[1].age = 30
            data[2].address = '深圳'
            // re-render  再次渲染
            render(data)
        })

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

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

上面代码遇到的问题:

  • DOM操作是昂贵的,js运行效率高;
  • 尽量减少DOM操作而不是推倒重来;
  • 项目越复杂影响越严重;

vdom是可以解决以上问题的。
这里将DOM操作的对比放在js层是为了提高效率,对比dom是为了找出真正需要改变的节点,而不是没变动的节点也都改了。这样才能尽量减少dom操作,才能提高效率。

Snabbdom

Snabbdom是一个开源的vdom的库。vdom是一类技术实现,就像 MVC,MVVM 一样,能实现 MVC,MVVM 的组件化的库有很多,不限于Vue和react这两个,vdom是一个通用的技术实现,能实现vdom的库也很多,不限于snabbdom这一个。

snabbdom的核心api:

在这里插入图片描述
snabbdom用法小栗子:

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

    <script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom.js"></script>
    <script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-class.js"></script>
    <script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-props.js"></script>
    <script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-style.js"></script>
    <script src="https://cdn.bootcss.com/snabbdom/0.7.1/snabbdom-eventlisteners.js"></script>
    <script src="https://cdn.bootcss.com/snabbdom/0.7.1/h.js"></script>
    <script type="text/javascript">
        var snabbdom = window.snabbdom

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

        // 定义 h
        var h = snabbdom.h

        var container = document.getElementById('container')

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

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

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

用snabbdom重写前面jQuery的写法:

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

    <script src="https://cdn.bootcss.com/snabbdom/0.7.0/snabbdom.js"></script>
    <script src="https://cdn.bootcss.com/snabbdom/0.7.0/snabbdom-class.js"></script>
    <script src="https://cdn.bootcss.com/snabbdom/0.7.0/snabbdom-props.js"></script>
    <script src="https://cdn.bootcss.com/snabbdom/0.7.0/snabbdom-style.js"></script>
    <script src="https://cdn.bootcss.com/snabbdom/0.7.0/snabbdom-eventlisteners.js"></script>
    <script src="https://cdn.bootcss.com/snabbdom/0.7.0/h.js"></script>
    <script type="text/javascript">
        var snabbdom = window.snabbdom
        // 定义关键函数 patch
        var patch = snabbdom.init([
            snabbdom_class,
            snabbdom_props,
            snabbdom_style,
            snabbdom_eventlisteners
        ])

        // 定义关键函数 h
        var h = snabbdom.h

        // 原始数据
        var data = [
            {
                name: '张三',
                age: '20',
                address: '北京'
            },
            {
                name: '李四',
                age: '21',
                address: '上海'
            },
            {
                name: '王五',
                age: '22',
                address: '广州'
            }
        ]
        // 把表头也放在 data 中
        data.unshift({
            name: '姓名',
            age: '年龄',
            address: '地址'
        })

        var container = document.getElementById('container')

        // 渲染函数
        var vnode
        function render(data) {
            var newVnode = h('table', {}, data.map(function (item) {
                var tds = []
                var i
                for (i in item) {
                    if (item.hasOwnProperty(i)) {
                        tds.push(h('td', {}, item[i] + ''))
                    }
                }
                return h('tr', {}, tds)
            }))

            if (vnode) {
                // re-render
                patch(vnode, newVnode)
            } else {
                // 初次渲染
                patch(container, newVnode)
            }

            // 存储当前的 vnode 结果
            vnode = newVnode
        }

        // 初次渲染
        render(data)


        var btnChange = document.getElementById('btn-change')
        btnChange.addEventListener('click', function () {
            data[1].age = 30
            data[2].address = '深圳'
            // re-render
            render(data)
        })

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

h函数,patch函数:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值