Virtual DOM 系列二:核心API

为了更好的研究Virtual DOM,我选择了snabbdom来学习。相比Vue来说,snabbdom对于研究虚拟DOM更好,因为它里面没有其他干扰的东西,而且源码也比较少,因此研究起来更方便。

1. 初次体验虚拟DOM的魅力

首先我们先用snabbdom重写之前的例子:

 

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <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.4.0/jquery.min.js"></script>
  <!-- 引入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>

  <script type="text/javascript">
    var snabbdom = window.snabbdom;
    //init patch function
    var patch = snabbdom.init([
      snabbdom_class,
      snabbdom_props,
      snabbdom_style,
      snabbdom_eventlisteners
    ]);
    // 定义h函数
    var h = snabbdom.h;

    var container = document.getElementById('container');
    
    var data = [{
      name: "张三",
      age: 24,
      address: "深圳"
      }, {
      name: "张三",
      age: 24,
      address: "深圳"
      }, {
      name: "张三",
      age: 24,
      address: "深圳"
    }];

    var oldVnode;
    function render(data) {
      var vnode = h('ul#list', {}, data.map(function (item) {
        return h('li', {}, item.name+' '+item.age+' '+item.address)
      }))
      if (!oldVnode) {
        //初始化页面渲染
        patch(container, vnode);
      } else {
        //对比原来的vnode和新生成的vnewnode,找出差异,只渲染修改的部分
        patch(oldVnode, vnode);
      }
      oldVnode = vnode;
    }

    $('#btn-change').click(function () {
      data[1].name = '李四';
      data[2].name = '王五';
      //修改后重新渲染
      render(data);
    })
    render(data); //初始化页面渲染
  </script>
</body>
</html>

  

点击change,发现只修改了有差异的地方。对比之前jquery清空整个div,性能上有很大提升,特别是在复杂应用上。

 

2. 实现原理

通过上面snabbdom的例子,我们发现有两个核心的API:

1. h函数(将真实dom映射成虚拟节点);

h('<html 标签名>',{属性},[children])//含有子节点的

h('<html 标签名>',{属性},'text'])//没有子节点,只有文本,如<p>this is VN</p>

2. patch函数(通过对比新旧虚拟节点,找出差异(diff算法),再把这些变化更新到真实dom中)

patch(container, vnode)//初次渲染

patch(oldVnode, newVnode); //re-render

posted @ 2019-04-29 16:29  濮成林  阅读(476)  评论(0编辑  收藏  举报