【virtual dom】虚拟DOM

  • vdom是什么,为何会存在vdom
  • vdom如何应用,核心API是什么
  • 介绍一下diff算法(vdom80%依赖diff算法)

★什么是vdom,为何会存在vdom
设计一个需求场景:将data数据展示成一个表格,随便修改一个信息,表格也跟着修改

<body>
<div id="container"></div>
<button id="change">修改</button>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script>
    var data=[
        {
            name:"张三",
            age:"20",
            address:"北京"
        },
        {
            name:"李四",
            age:"20",
            address:"上海"
        },
        {
            name:"王五",
            age:"20",
            address:"广州"
        }
    ];
    //渲染函数
    function render(data){
        var $container=$('#container');
        //清空现有的内容
        $container.html("");
        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);
    };
    //点击修改信息
    $('#change').click(function(){
        data[1].age=30;
        data[2].address='深圳';
        render(data);
    });
    //初次渲染
    render(data);
</script>
</body>

用jQuery实现的不足:

  • DOM操作是昂贵的,JS运行效率高
  • 尽量减少DOM操作,而不是推到重来
  • 项目越复杂,影响就越严重
  • vdom即可解决该问题

浏览器自己创造的实际DOM元素中有许多属性和方法,但用JS模拟的虚拟DOM结构很简单。JS模拟的虚拟DOM能尽量减少实际DOM的操作,提高性能。
JS模拟的虚拟DOM结构如下:
在这里插入图片描述
在这里插入图片描述
回答提出的问题(什么是vdom,为何会存在vdom):

  1. virtual dom,虚拟DOM
  2. 是用JS模拟DOM结构(原因:为了提高性能,我们需要用JS找出哪些DOM要操作,哪些DOM不用操作,这需要逻辑运算,即需要图灵完备的语言,前端即JS)
  3. 将DOM对比操作放在JS层,提高效率

★vdom如何应用,核心API是什么

说到vdom,就会想到snabdom,vue2.0里面的虚拟dom就是通过snabdom来实现的。
snabdom部分源码:
在这里插入图片描述
vdom是JS模拟的dom元素,vnode是JS模拟的node节点。

从snabdom的源码中就可以看到,实现虚拟dom最核心的API是两个函数:h函数、patch函数。

h函数可以生成JS模拟的DOM结构,h函数的三个参数分别对应用JS模拟的DOM节点里的tag,attrs,children,例:
在这里插入图片描述
在这里插入图片描述
h函数的第一个参数是’tagName.className’或者’tagName#Id’,第二个参数为一个对象,里面可以是事件或者样式或者属性值那些,第三个参数可以为一个,也可以为多个(数组)。

介绍snabdom里的patch函数:
在这里插入图片描述
patch函数有两个用法:

  1. patch(container,vnode); 意思是将vnode表示的虚拟DOM节点全部塞到container中。
  2. patch(vnode,newVnode); 第一个参数是旧的vnode,第二个参数为新的vnode,意思是将新旧vnode进行对比,没改动的地方不变,只改动变了的地方。

重写前面将数据渲染成表格的例子:

<body>
    <div id="container"></div>
    <button id="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>

在调试窗口的Element中可以看到,只有修改了的DOM重新渲染了,而不是推到重来,减少了DOM操作,提高了性能。

问题解答:
关于vdom如何应用,已经在上面的demo中演示过了。
vdom的核心API总结:

  • h(‘标签名’,{属性},[子元素]); 多个子元素可以这样写
  • h(‘标签名’,{属性},‘子元素’); 一个子元素可以这样写
  • patch(container,vnode);
  • patch(vnode,newVnode);

★介绍一下diff算法

1.什么是diff算法
2.去繁就简
3.diff算法在vdom中干什么
4.diff算法的实现流程

什么是diff算法:
diff是linux中的命令,用于找出两个文本文件的异同(diff log1.txt log2.txt )
git diff 是提交代码时与上一版本的对比。
所以diff不是vdom独创的算法(代码对比,一直存在),vdom中使用diff算法是为了找出需要需要更新的节点(只是对象变成了JS对象)。
diff算法的实现过程中有四个函数:

  • patch(container,vnode);
  • patch(vnode,newVnode);
  • createElement(vnode);
  • updateChildren(vnode,newVnode);
    核心逻辑在 createElement(vnode);和updateChildren(vnode,newVnode);函数中

去繁就简
diff算法非常复杂,实现难度很大,源码量很大,去繁就简,总结核心流程
diff算法在vdom中干什么
在这里插入图片描述

  • DOM操作是昂贵的,因此尽量减少DOM操作
  • 需要找到本次DOM必须更新的节点来更新,其他的不更新
  • 找出前后两个vdom之间差异的过程就需要diff算法
  • 和diff算法在其他方面的应用对比,它在vdom中的应用只是文本对象变成了节点元素

diff算法的实现流程

  • patch(container,vnode); 虚拟DOM变成实际DOM,即第一个patch的实现
  • patch(vnode,newVnode); 对比更新DOM节点,即第二个patch函数的实现

那怎么由模拟的DOM结构生成实际的DOM结构呢 patch(container,vnode)
在这里插入图片描述

patch(vnode,newVnode)的实现

模拟DOM中的节点必须和真实的DOM对应上,因为找出区别更新的时候,必须得知道更新在哪个地方,所以vdom和真实dom必须有对应关系

对比vnode和newVnode
在这里插入图片描述
在这里插入图片描述
对比vnode和newVnode发现,第二个li元素不同,且增加了第三个li元素
在这里插入图片描述
对比出来不同后,它的实现是这样的
在这里插入图片描述
tag一样就直接递归对比子元素,不一样就直接替换

diff的实现过程总结:

  • patch(container,vnode);
  • patch(vnode,newVnode);
  • createElement(vnode);
  • updateChildren(vnode,newVnode);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值