虚拟dom应用

vdom如何应用,核心api是什么
1、介绍snabbdom(开源社区用的多,vue2用的是他)
首先回顾下之前的vdom格式
真实的dom
<body>
  <ul id="list">
    <li class="item">item 1</li>
    <li class="item">item 2</li>
  </ul>
</body>

 

 

js模拟的dom
{
  tag: 'ul',
  attrs: {
    id: 'list'
  },
  children:[{
    tag: 'li',
    attrs: { className: 'item' },
    children: ['item 1']
  },{
    tag: 'li',
    attrs: { className: 'item'},
    children:['item 2']
  }]
}

用js模拟的体量非常小。

 

看snabbdom里面的介绍。一个h函数,一个patch函数,就是vdom最主要的api。看h函数传的是什么。

第一个是标签div,标签对应的id #container,标签对应的class,two,classes。
第二个参数是,这个标签绑定了一个事件,函数叫someFn。
第三个是个数组,数组又是h函数,传入标签,属性,文本
第一次渲染是全部渲染到浏览器中,第二次渲染,数据源有所改变,根据改变重新生成一个newVnode,这个时候再patch。这个时候patch的时候,会进行一个对比,这个对比是只找出需要更新的那部分来更新

 

上面例子的模拟
<!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 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>
      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);

      //模拟改变
      var btnChange = document.getElementById('btn-change');
      btnChange.addEventListener('click', function(){
        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>

item1没有渲染,item b, item3闪烁了



2、重做之前的demo

 

<!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 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>
    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.unshift({
      name: '姓名',
      age: '年龄',
      address: '地址'
    });

    var container = document.getElementById('container');
    var btnChange = document.getElementById('btn-change');
 
    // 渲染函数
    var vnode;
    function render(data) {
      var newVnode = h('table',{}, data.map(function(item){
        var tds = [];
        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 = newVnode;
    }
    render(data);

    btnChange.addEventListener('click', function(){
      data[1].age = 30;
      data[2].address = '深圳';
      // re-render
      render(data);
    })
  </script>
</body>
</html>

再查看dom,不再是整个table渲染。就只更新改变的dom。



3、核心api
  h('<标签名>', {...属性}, [...子元素])
  h('<标签名>', {...属性}, '...')
 
  patch(container, vnode)
  patch(vnode, newVnode)

 

posted @ 2019-06-16 08:23  wzndkj  阅读(310)  评论(0编辑  收藏  举报