vue2.0的虚拟DOM渲染思路分析


Posted in Javascript onAugust 09, 2018

1、为什么需要虚拟DOM

前面我们从零开始写了一个简单的类Vue框架(文章链接),其中的模板解析和渲染是通过Compile函数来完成的,采用了文档碎片代替了直接对页面中DOM元素的操作,在完成数据的更改后通过appendChild函数将真实的DOM插入到页面。

虽然采用的是文档碎片,但是操作的还是真实的DOM。

而我们知道操作DOM的代价是昂贵的,所以vue2.0采用了虚拟DOM来代替对真实DOM的操作,最后通过某种机制来完成对真实DOM的更新,渲染视图。

所谓的虚拟DOM,其实就是 用JS来模拟DOM结构,把DOM的变化操作放在JS层来做,尽量减少对DOM的操作 (个人认为主要是因为操作JS比操作DOM快了不知道多少倍,JS运行效率高)。然后对比前后两次的虚拟DOM的变化,只重新渲染变化了的部分,而没有变化的部分则不会重新渲染。

比如我们有如下的DOM结构。

<ul id="list">
   <li class="item1">Item 1</li>
   <li class="item2">Item 2</li>
</ul>

我们完全可以用JS对象模拟上面的DOM结构,模拟后就会变成下面的这种结构。

var vdom = {
  tag: 'ul',
  attr: {
    id: 'list',
  },
  children: [
    {
      tag: 'li',
      attrs: {
        className: 'item',
        children: ['Item 1']
      },
    },
    {
      tag: 'li',
      attrs: {
        className: 'item',
        children: ['Item 2']
      }
    }
  ]
}

必须要注意一点的是:JS模拟的DOM结构并没有模拟所有DOM节点上的属性、方法(因为DOM节点本身的属性非常多,这也是DOM操作耗性能的一个点),而是只模拟了一部分和数据操作相关的属性和方法。

2、怎么使用虚拟DOM

Vue 在 2.0 版本引入了 vdom 。其 vdom 是基于 snabbdom 库所做的修改。snabbdom是一个开源的vdom库。

snabbdom的主要作用就是 将传入的JS模拟的DOM结构转换成虚拟的DOM节点。

先通过其中的h函数将JS模拟的DOM结构 转换成虚拟DOM之后,再通过其中的patch函数将虚拟DOM转换成真实的DOM渲染到页面中。

为了保证页面的最小化渲染,snabbdom引入了Diff算法 ,通过Diff算法找出前后两个虚拟DOM之间的差异,只更新改变了的DOM节点,而不重新渲染为改变的DOM节点。

在这里我不打算分析snabbdom的源码来解释到底snabbdom是怎么干成这件事的(主要是现阶段没到那个水平,哈哈。再者已经有很多同学做过类似的分析,相关链接附在文章末尾)。

我会从snabbdom的使用角度来看Vue中的虚拟DOM是如何完成视图渲染的。

我们先看一下snabbdom中两个核心API的功能。

h()函数:将传入的JS模拟的DOM结构模板转换成vnode。(vnode是一个纯JS对象)
patch()函数:将虚拟的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>
  <!-- 引入snabbdom库,先不必纠结为什么这样引入,以及每个文件的作用。本篇文章只是介绍一下虚拟DOM的工作方式,并不涉及原理解析
  主要是因为博主目前功力尚浅,有兴趣的小伙伴可以另行研究 -->
  <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>
    //定义patch函数
    var patch = snabbdom.init([
      snabbdom_class,
      snabbdom_props,
      snabbdom_style,
      snabbdom_eventlisteners
    ])
    //定义h函数
    var h = snabbdom.h;
    //生成一个vnode
    var vnode = h('ul#list',{},[
      h('li.item',{},['Item 1']),
      h('li.item',{},['Item 2']),
    ])

 //console.log(vnode);
    //获取container
    var container = document.getElementById('container');
    patch(container,vnode);//初次渲染
    var btn = document.getElementById('btn-change');
    btn.onclick = function() {
      var newVnode = h('ul#list',{},[
        h('li.item',{},['Item 1']),
        h('li.item',{},['Item B']),
        h('li.item',{},['Item 3']),
      ])
      patch(vnode,newVnode);//再次渲染



 vnode = newVnode;//将修改后的newVnode赋值给vnode



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

思路分析:

  • 我们先通过h函数创建一个虚拟DOM节点,通过patch函数将虚拟DOM渲染到页面。
  • 点击btn按钮时,更新ul#list列表的数据,改变了第二个li元素的值并且新增了一个li元素,第一个li元素的值并没有改变。我们再次通过patch函数将更新后的数据渲染到页面上。可以看到只有第二个和第三个li发生了更新,而第一个li由于没有改变,并没有重新渲染。

vue2.0的虚拟DOM渲染思路分析

vue中的模板解析和渲染的核心就是:通过类似snabbdom的h()和patch()的函数,先将模板解析成vnode,如果是初次渲染,则通过patch(container,vnode)将vnode渲染至页面,如果是二次渲染,则通过patch(vnode,newVnode),先通过Diff算法比较原vnode和newVnode的差异,以最小的代价重新渲染页面。

总结

以上所述是小编给大家介绍的vue2.0的虚拟DOM渲染思路分析,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Javascript 相关文章推荐
jQuery 树形结构的选择器
Feb 15 Javascript
JS判断客服QQ号在线还是离线状态的方法
Jan 13 Javascript
jQuery实现点击按钮弹出可关闭层的浮动层插件
Sep 19 Javascript
jQuery+canvas实现简单的球体斜抛及颜色动态变换效果
Jan 28 Javascript
不能不知道的10个angularjs英文学习网站
Mar 23 Javascript
原生js实现简单的焦点图效果实例
Dec 14 Javascript
Vue.js组件间的循环引用方法示例
Dec 27 Javascript
解决Vue.js 2.0 有时双向绑定img src属性失败的问题
Mar 14 Javascript
Vue实现侧边菜单栏手风琴效果实例代码
May 31 Javascript
更强大的vue ssr实现预取数据的方式
Jul 19 Javascript
JavaScript实现轮播图特效
Apr 10 Javascript
JavaScript中MutationObServer监听DOM元素详情
Nov 27 Javascript
Angular动画实现的2种方式以及添加购物车动画实例代码
Aug 09 #Javascript
Vue.js 通过jQuery ajax获取数据实现更新后重新渲染页面的方法
Aug 09 #jQuery
详解Vue开发微信H5微信分享签名失败问题解决方案
Aug 09 #Javascript
JQuery Ajax动态加载Table数据的实例讲解
Aug 09 #jQuery
详解在React中跨组件分发状态的三种方法
Aug 09 #Javascript
使用jquery DataTable和ajax向页面显示数据列表的方法
Aug 09 #jQuery
React中如何引入Angular组件详解
Aug 09 #Javascript
You might like
ThinkPHP3.1.3版本新特性概述
2014/06/19 PHP
Yii中srbac权限扩展模块工作原理与用法分析
2016/07/14 PHP
Linux系统中为php添加pcntl扩展
2016/08/28 PHP
Js如何判断客户端是PC还是手持设备简单分析
2012/11/22 Javascript
js或者jquery判断图片是否加载完成实现代码
2013/03/20 Javascript
详谈jQuery操纵DOM元素属性 attr()和removeAtrr()方法
2015/01/22 Javascript
javaScript基础语法介绍
2015/02/28 Javascript
javascript实现鼠标移到Image上方时显示文字效果的方法
2015/08/07 Javascript
微信js-sdk分享功能接口常用逻辑封装示例
2016/10/13 Javascript
使用ES6语法重构React代码详解
2017/05/09 Javascript
Angular2 父子组件数据通信实例
2017/06/22 Javascript
vue 封装自定义组件之tabal列表编辑单元格组件实例代码
2017/09/07 Javascript
jQuery基于cookie实现换肤功能实例
2017/10/14 jQuery
微信小程序倒计时功能实例代码
2018/07/17 Javascript
JS对象和字符串之间互换操作实例分析
2019/02/02 Javascript
微信小程序五子棋游戏的棋盘,重置,对弈实现方法【附demo源码下载】
2019/02/20 Javascript
JavaScript canvas绘制渐变颜色的矩形
2020/02/18 Javascript
vue 基于abstract 路由模式 实现页面内嵌的示例代码
2020/12/14 Vue.js
python获取糗百图片代码实例
2013/12/18 Python
Python的Bottle框架中实现最基本的get和post的方法的教程
2015/04/30 Python
pytorch numpy list类型之间的相互转换实例
2019/08/18 Python
Django框架创建项目的方法入门教程
2019/11/04 Python
基于python实现破解滑动验证码过程解析
2020/05/28 Python
Python实现查找数据库最接近的数据
2020/06/08 Python
python和JavaScript哪个容易上手
2020/06/23 Python
css3实现3d旋转动画特效
2015/03/10 HTML / CSS
Canvas环形饼图与手势控制的实现代码
2019/11/08 HTML / CSS
学生会宣传部部长竞选演讲稿
2014/04/25 职场文书
学生会竞选演讲稿怎么写
2014/08/26 职场文书
离职证明范本(5篇)
2014/09/19 职场文书
教师教育教学随笔
2015/08/15 职场文书
中学音乐课教学反思
2016/02/18 职场文书
如何写好竞聘报告
2019/04/03 职场文书
导游词之平津战役纪念馆
2019/11/04 职场文书
浅谈Python协程asyncio
2021/06/20 Python
JS中forEach()、map()、every()、some()和filter()的用法
2022/05/11 Javascript