博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
javascript基础修炼(10)——VirtualDOM和基本DFS
阅读量:7064 次
发布时间:2019-06-28

本文共 3299 字,大约阅读时间需要 10 分钟。

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

1. Virtual-DOM是什么

Virtual-DOM,即虚拟DOM树。浏览器在解析文件时,会将html文档转换为document对象,在浏览器环境中运行的脚本文件都可以获取到它,通过操作document对象暴露的接口可以直接操作页面上的DOM节点。但是DOM读写是非常耗性能的,很容易触发不必要的重绘和重排,为了更好地处理DOM操作,Virtual-DOM技术就诞生了。Virtual-DOM就是在javascript中模拟真实DOM的结构,通过数据追踪和状态对比来减少对于真实DOM的操作,以此来提高程序的效率的一种技术。

Virtual-DOM技术是前端高性能的基石,它是真实document对象的抽象,通过对比新旧Virtual-DOM的区别,找出发生变化的DOM节点,再利用算法得到相对更合理的DOM节点修改方案,最终再将方案应用在document对象上来改变页面的展示内容。

主流前端SPA框架都离不开【Virtual-DOM模型 + DOM-Diff算法 + 生命周期钩子】这样的核心模型。

2. Virtual-DOM的基本结构

在上一篇博文《javascript基础修炼(9)——MVVM中双向数据绑定的基本原理》中,我们通过document.getElementById()从真实DOM中获得了带有自定义属性的待解析结构,这里是有一些问题的,实际的过程是先解析模板字符串得到虚拟DOM树,最后生成真实的DOM树。

实际上我们在使用SPA框架时所编写的html模板,并没有被直接当做DOM片段加载到页面上使用,而是将文件当做字符串读入到程序中,然后通过解析来生成Virtual-DOM树,接着通过SPA框架的渲染函数来生成必要的片段后才生成真实的DOM节点。例如我们要生成下文示例的HTML片段(为了方便演示,示例中只涉及了类名和文本节点):

   
header-zone
core-content
暂未开发

我们需要构建出一个简易模型来表达上面的结构:

virtualDom = {    name:"body",    props:{        className:"main"    },    children:[{        name:"div",        props:{...},        children:[...]      },{        name:"div",        props:{...},        children:[...]      },{        name:"div",        props:{...},        children:[...]      }]}

建立一个生成虚拟节点的辅助函数:

//构建DOM节点的辅助函数function h(name, props, children) {    return {        name:name,        props:props,        children:children    }}//手动生成virtual-DOMvar tree = h('body',{className:'main'},[       h('div',{className:'sideBar'},[          h('ul',{className:'sideBarContainer'},[               h('li',{className:'sideBarItem'},['sidebar-1']),               h('li',{className:'sideBarItem'},['sidebar-2']),               h('li',{className:'sideBarItem'},['sidebar-3']),            ])        ]),       h('div',{className:'mainContent'},[           h('div',{className:'header'},['header-zone']),           h('div',{className:'coreContent'},['core-content']),           h('div',{className:'footer'},['footer-zone']),        ]),       h('div',{className:'rightSide'},['暂未开发'])    ]);

通过上面的方法得到的tree对象就涵盖了模板片段中的结构和关键信息。实际开发中并不需要像上面一样手动来填写DOM结构,可以将模板字符串挂载到离线DOM节点上,然后在递归解析的同时来构建Virtual-DOM就可以了。

3. 使用DFS从Virtual-DOM生成DOM

至此我们完成了模板的编译,也得到了Virtual-DOM对象,但它似乎并没有什么用处,毕竟我们已经完成了对模板的解析,渲染出页面没什么问题,其实Virtual-DOM对于首屏来说并没有什么特别重要的意义,它的价值在模型和视图发生变化时才会体现。上一篇博文的末尾我们已经提到了更新视图时的效率问题,当数据模型发生变化后,我们需要一个方法来收集所有需要修改的DOM,并为之提供高效的修改方式(你总不能一有变化就把整个网页重新渲染,或者让数据模型各自去修改各自绑定的DOM吧)。那么为了能够收集所有DOM节点的变化,我们就需要遍历所有节点。

对数据结构和算法有一定了解的读者很容易想到,遍历解析一个Virtual-DOM实际上就是对其进行先序深度优先遍历(Pre-Order Depth-First-Search),本节中,我们先预热一下,使用这种方式来复现一下DOM结构。

function dfswalking(tree) {    var _childrenLength;    //执行动作    if (typeof tree.children[0] === 'string') {        console.log(`<${tree.name} class="${tree.props.className}">${tree.children[0]}
`); } else { console.log(`<${tree.name} class="${tree.props.className}"> -->`); for(var i = 0, _childrenLength = tree.children.length; i < _childrenLength; i++){ dfswalking(tree.children[i]); } }}

本例中仅打印出字符串的方式来展示,可以在控制台看到输出结果:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

下一篇博文中将分析如何通过domDiff(oldTree, newTree)的方法通过同样的遍历方法来收集变化并批量更新视图。

4. 声明

本篇只是部分原理的学习笔记,并不代表框架真实源码的实现逻辑。

转载于:https://www.cnblogs.com/dashnowords/p/10030036.html

你可能感兴趣的文章
【Linux】目录权限与文件权限
查看>>
如何将阿拉伯数字每三位一逗号分隔,如:15000000转化为15,000,000
查看>>
select的使用(一)
查看>>
[leetcode]Search a 2D Matrix @ Python
查看>>
java.io.BufferedOutputStream 源码分析
查看>>
Load resources from classpath in Java--reference
查看>>
关于LightMapping和NavMesh烘焙的动态载入
查看>>
(转)Android中使用ormlite实现持久化(一)--HelloOrmLite
查看>>
C语言近程型(near)和远程型(far)的区别是什么?
查看>>
jQuery选择器总结
查看>>
《Continuous Delivery》 Notes 1: The problem of delivering software
查看>>
java android 将小数度数转换为度分秒格式
查看>>
一张图知道HTML5布局(图)
查看>>
LINQ To SQL在N层应用程序中的CUD操作、批量删除、批量更新
查看>>
谈谈javascript语法里一些难点问题(一)
查看>>
【BZOJ】1082: [SCOI2005]栅栏(二分+dfs)
查看>>
通过递归组合多维数组!
查看>>
ocp 1Z0-051 23-70题解析
查看>>
关于MFLAGS与MAKEFLAGS
查看>>
NotePad++ for PHP
查看>>