具体实施方式
为了更好的理解上述技术方案,下面通过附图以及具体实施例对本说明书实施例的技术方案做详细的说明,应当理解本说明书实施例以及实施例中的具体特征是对本说明书实施例技术方案的详细的说明,而不是对本说明书技术方案的限定,在不冲突的情况下,本说明书实施例以及实施例中的技术特征可以相互组合。
第一方面,本说明书实施例提供一种局部页面动态渲染方法,请参考图1,包括步骤S101-S102。
S101:在检测到目标页面中存在数据变更情况下,获得与变更前的视图页面的第一虚拟DOM树以及变更后的视图页面的第二虚拟DOM树,其中,针对所述虚拟DOM树和所述第二虚拟DOM树创建有同一虚拟索引,针对真实DOM树创建有真实索引;
S102:按虚拟索引顺序依次对所述第一虚拟DOM树中节点与所述第二虚拟DOM树中的节点进行对比,确定所述第一虚拟DOM树和所述第二虚拟DOM树中在当前虚拟索引位置处的节点的第一变更状态,以及确定所述第一虚拟DOM树和所述第二虚拟DOM树中在前一虚拟索引位置处的节点的第二变更状态,根据相邻两个虚拟索引位置处节点的变更状态与预设渲染操作间预设的对应关系,确定与所述第二变更状态至所述第一变更状态对应的目标预设渲染操作,按所述目标预设渲染操作对所述真实DOM树中对应真实索引位置处的节点进行渲染,直至完成最后一个虚拟索引位置所对应的真实索引位置处的节点的渲染。
具体的,本实施例中的局部页面动态渲染方法主要应用于前端展示的应用程序,如:浏览器。在现有的前端展示解决方案中,应用较为普遍包括MVVM框架,MVVM为前端时下流行的最新框架方案统称,是对传统的MVC(数据、视图、控制)的改进,M(数据)V(视图)VM(视图数据绑定)。由于页面通常是由对象组成的,这些对象被组织在一个树形结构中,另外,页面中的对象通常是以模型的形式表示的,用来表示上述对象所在树形结构的标准模型称为DOM(Document Object Model,文档对象模型)。
在进行页面渲染时,页面更新是前端基于待更新到页面的数据更新页面的过程,即基于待更新到页面的数据,更新真实DOM。如果直接对真实DOM进行操作,会非常复杂且低效。相较于真实DOM,原生的JavaScript对象处理起来更快,而且更简单。DOM树上的结构、属性信息都可以很容易地用JavaScript对象表示出来。所以,在MVVM框架下,React系列使用了基于JSX语法的DOMDiff方案,其将数据和视图进行绑定,当数据变更时生成新视图和老视图对比,进行局部更新。其中,JSX是facebook发明的一种语法规范,继承原有js语法扩充了主表达式,使得html的DOM能够成为一个变量,并称之为虚拟DOM(VirtualDOM),VirtualDOM对应真实DOM的js变量,一般为一个DOM节点,也有可能为一个文本节点。进而,可以采用DOMDiff的更新方式,即当数据发生变更时,绑定的视图随之发生变更,可以用新渲染的虚拟DOM树去和旧的虚拟DOM树进行对比,记录这两棵树差异。记录下来的不同就是需要对页面真正的DOM操作,然后把它们应用在真正的DOM树上,页面就变更了,避免整体视图更新的消耗。
但是,采用DOMDiff更新方式时,所有可变数据在DOM中以SPAN标签包裹(老版)或注释标签包裹(新版)。这会对原有DOM造成侵入、多余数据、多余变更侦听的缺点。
例如:<div>{'a'}</div>会被渲染为<div><span>a</span></div>(老版)或<div><!-->text start<-->a<!-->text end<--></div>(新版)。所有js文本变量在输出时需要被包裹以便识别。又如:<div>{'a'}{'b'}</div>会被渲染为<div><span>a</span><span>b</span></div>(老版)或<div><!-->textstart<-->ab<!-->text end<--></div>(新版)。老版会为每个变量包裹span标签,新版改进了一点会为文本节点合集包裹注释标签。以老版举例,为每个变量包裹span标签目的是方便DOMDiff,其原因是VirtualDOM和真实DOM并非一一对应,真实DOM存在文本节点合并而VirtualDOM没有。例如:<div>{'a'}{'b'}</div>在VirtualDOM中有a和b两个VirtualDOM,输出为DOM后只有一个ab文本节点。此时只有a一个发生变化为c时,真实DOM的文本节点应该变为cb。如果渲染为<div><span>a</span><span>b</span></div>的话,只需要将第一个a变为c即可,不必考虑合并的问题,大大简化逻辑处理。由于span标签为行内标签,注释标签更是会被渲染忽略,所以最终输出一般情况下看起来和预期相符,只是多余了一些不必要的数据。而注释标签也会占用子节点空间,本身只有一个文本节点变成了注释节点、文本节点、注释节点这样3个,多余的标签在发生DOMDiff变更时会触发DOMSubtreeModified等事件,所以,会对原有DOM造成侵入、多余数据、多余变更侦听等缺点。
为了解决上述问题,在本实施例中,采用不同于便签包裹的方式进行局部页面动态渲染的方法。首先通过步骤S101,在检测到目标页面中存在数据变更情况下,获得与变更前的视图页面的第一虚拟DOM树以及变更后的视图页面的第二虚拟DOM树。
具体的,在本实施例中,React中维护有状态转移的过程,在检测到目标页面中存在数据变更时,视图页面的状态产生变化,就会触发render函数构建新的第二虚拟DOM树。
进而,本实施例中的方案,预先构建了相邻两个虚拟索引位置处节点的变更状态与预设渲染操作间预设的对应关系,该对应关系可按如图2所示的预设状态转移图配置,该图包含了虚拟DOM树中节点变更的所有状态,每两个状态间的转移对应了不同的预设渲染操作。由于在虚拟DOM树中的VirtualDOM分为2种:DOM节点记作D,文本节点记作T。所以,图2所示的状态转移图中包括:初始状态0、文本节点至文本节点变更状态1(T2T)、文本节点至DOM节点变更状态2(T2D)、DOM节点至文本节点变更状态3(D2T)、DOM节点至DOM节点变更状态4(D2D),另有添加DOM、删除DOM、添加文本、删除文本4种状态,因为状态机最小化原则且每种情况等价于上述某一状态,所以最后合并仍为上述5种状态。状态0可跳转至状态1、状态2、状态3、状态4。状态1、状态2、状态3、状态4间可相互跳转。每两个状态间的跳转均配置有与之对应的预设渲染操作。
由于在虚拟DOM树中可能会包括空白变量,而空白变量在真实渲染时会优化该空白节点,不再渲染。由于状态机不能识别空的字符串,所以确保状态机正确运行,本实施例中的方法还包括如下步骤:
在对目标页面初始化渲染后,获得初始页面的初始虚拟DOM树;遍历初始虚拟DOM树,确定初始虚拟DOM树中所包含的空白变量;在每个空白变量位置处插入空文本节点。
其中,空白变量包括空字符串、null字段、空数组和undefined字段中的任意一种。
具体的,在本实施例中,目标页面的初始化渲染过程中,重点为渲染结束将视图结果作为html输出后,随之紧接遍历初始DOM树中的VirtualDOM和对应的DOM节点。当发现VirtualDOM中有空白变量时在此位置插入一个空文本节点。具体的,空白变量包括:空字符串、null、空数组、undefined。空文本节点用js的api:document.createTextNode(”)来创建。针对null变量,例如:<div>{null}</div>由于null是个空文本,结果输出为空,div节点下没有子节点,在其下创建一个空文本节点插入。又如:<div>{[]}</div>,空数组也是个空文本,实际渲染时也为空,div节点下没有子节点,在其下创建一个空文本节点插入。空字符串和undefined也采用同样的方式。另一种情况中,<div>text{undefined}</div>,undefined是个空文本,但由于相邻前方有个纯文本text,结果输出为<div>text</div>,两者合并后整体不是空文本,所以无需创建空文本节点插入。
进而,可采用步骤S102,将第一虚拟DOM树中节点与第二虚拟DOM树中的节点按虚拟索引位置依次进行对比,根据对比结果,按真实索引位置依次对真实DOM树中对应节点进行渲染操作,直至对比至最后一个虚拟索引位置。
具体的,本实施例中,设置2种索引用以遍历辅助,index作为VirtualDOM的索引,即虚拟索引位置,start用作计算真实DOM树的索引,即真实索引位置,index和start均从0开始。本实施例中还引入了索引记录VirtualRange,VirtualRange中记录着虚拟索引内容,利用VirtualRange记录的内容进行页面更新内容。进而,在图2中,0为初始状态,1、2、3、4对应T2T、T2D、D2T、D2D状态。0到1、2、3、4的状态上分别对应4种操作:f0、f1、f2、f3,1、2、3、4之间互相转态转换各对应一种操作,共16种操作,整体统计有20种操作。下面针对每一种操作具体举例说明阐述。
针对初始状态跳转至T2T状态,对应预设渲染操作f0,包括:创建索引记录,索引记录中记录有虚拟索引内容,虚拟索引内容为第二虚拟DOM树中当前虚拟索引位置处的文本内容,如果第二虚拟DOM树中当前虚拟索引位置处的文本内容与第一虚拟DOM树中当前虚拟索引位置处的文本内容不一致,标记真实DOM树中当前真实索引位置的内容需要更新。
具体的,预设渲染操作f0包括记录index和start为新VirtualRange的索引,VirtualRange中虚拟索引内容为第二虚拟DOM树中当前虚拟索引位置处的文本内容,对比老文本和新文本是否相等,不相等情况即第二虚拟DOM树中当前虚拟索引位置处的文本内容与第一虚拟DOM树中当前虚拟索引位置处的文本内容不一致,标记此VirtualRange需要更新,也就是标记真实DOM树中当前真实索引位置的内容需要更新。
例如:<div>{'str1'}</div>变为<div>{'str2'}</div>。div标签视为环境标签不涉及DOMDiff,仅对其子节点进行过程说明。本例仅1个文本节点变化由状态0转换为状态1,index和start均为0,由于第一虚拟DOM树与第二虚拟DOM树中index(0)对应的文本不相等,所以此VirtualRange需要更新,将索引为index(0)和start(0)的文本节点('str1')均更新为新的('str2'),标记真实DOM树中start(0)位置需要更新。
针对T2T状态跳转至T2T状态,对应预设渲染操作d0,包括:创建索引记录,索引记录中记录的虚拟索引内容为在第二虚拟DOM树中当前虚拟索引位置处的文本节点的内容与相邻的上一个文本节点对应的索引记录中的虚拟索引内容的第一合并内容,确定在第一虚拟DOM树中包括当前虚拟索引位置处的节点在内的前面连续的文本节点对应的第二合并内容,如果第一合并内容和第二合并内容不一致,标记真实DOM树当前真实索引位置的内容需要更新。
具体的,创建VirtualRange,记录虚拟索引内容第二虚拟DOM树中当前虚拟索引位置处的文本节点的内容与相邻的上一个文本节点对应的索引记录中的虚拟索引内容的第一合并内容。再确定第一虚拟DOM树中包括当前虚拟索引位置处的节点在内的前面连续的文本节点对应的第二合并内容,对比第一合并内容盒第二合并内容是否相等,不相等的话标记此VirtualRange需要更新,即标记真实DOM树当前真实索引位置的内容需要更新。
例如:<div>a{'b'}</div>变为<div>a{'c'}</div>。遍历第1步与上述类似,不过a文本并未发生变化所以没有标记需要更新。遍历第2步,对比发现'ab'与'ac'不相等,标记更新,将索引为index(0)和start(0)的文本节点('ab')修改为新的('ac')。
针对T2T状态跳转至T2D状态,对应预设渲染操作d2,包括:获得当前虚拟索引位置的前一个虚拟索引位置对应的索引记录,如果索引记录中标记真实DOM树当前真实索引位置的内容需要更新,则将真实DOM树中当前真实索引位置处的文本节点内容变更为索引记录中的虚拟索引内容,将真实DOM树的当前真实索引位置加1,将第二虚拟DOM树中的当前虚拟索引位置处的DOM节点插入真实DOM树的当前真实索引位置,将真实DOM树的当前真实索引位置加1。
具体的,检查前一位置处的VirtualRange(若有),如果需要更新的话则更新,即检查标记是否需要对真实DOM树当前真实索引位置的内容更新,如果有的话,直接按此VirtualRange种的虚拟索引内容进行更新,start++,将当前的index的VirtualDOM插入到start的位置,start++。
例如:<div>a{'b'}</div>变为<div>a<span></span></div>。遍历第1步文本a并未发生变化。遍历第2步发现之前的VirtualRange发生变化(ab变为a),标记更新index(0)和start(0)的文本节点,更新后为a,start++为1,将span节点插入到start(1)的位置,start++为start(2)。
针对T2T状态跳转至D2T状态,对应预设渲染操作b1,包括:获得当前虚拟索引位置的前一虚拟索引位置对应的索引记录,如果索引记录中标记真实DOM树当前真实索引位置的内容需要更新,则将真实DOM树中当前真实索引位置处的文本节点的内容变更为索引记录中的虚拟索引内容,移除真实DOM树的当前真实索引位置加1处的节点。
b1:检查之前的VirtualRange(若有),如果需要更新的话则更新;移除start+1位置的节点。例如:<div>a<span></span></div>变为<div>a{'b'}</div>。遍历第1步文本a并未发生变化,遍历第2步发现之前的VirtualRange发生变化(a变为ab),标记更新index(0)和start(0)的文本节点,移除start+1(1)的span节点。
针对T2T状态跳转至D2D状态,对应预设渲染操作d3,包括:将真实DOM树的当前真实索引位置加1,如果第二虚拟DOM树中当前虚拟索引位置处的DOM节点与第一虚拟DOM树中当前虚拟索引位置处的DOM节点不一致,将真实DOM树的当前真实索引位置处的DOM节点更新为第二虚拟DOM树中当前虚拟索引位置处的DOM节点,将真实DOM树的当前真实索引位置加1。
具体的,start++,检查第一虚拟DOM树和第二虚拟DOM树中当前虚拟索引位置处的DOM节点是否变更,如果变更,然后进行更新;start++。
例如:<div>a<span></span></div>变为<div>a<b/></div>。遍历第1步文本节点内容没变,遍历第2步start++为1,发现span标签变为b标签,进行更新替换,start++为start(2)。
针对初始状态跳转至T2D状态,对应预设渲染操作f2,包括:将真实DOM树的当前真实索引位置由文本节点变更为第二虚拟DOM树中当前虚拟索引位置处的DOM节点,将真实DOM树的当前真实索引位置加1。
具体的,对真实DOM节点当前真实索引位置进行新旧节点替换,即由文本节点变为DOM节点;start++。
例如:<div>a</div>变为<div><span></span></div>。将index(0)和start(0)的位置,将文本节点a替换为span标签;start++为1。
针对T2D状态跳转至T2D,对应预设渲染操作c2,包括:在真实DOM树的当前真实索引位置处插入第二虚拟DOM树中当前虚拟索引位置处的DOM节点,将真实DOM树的当前真实索引位置加1。
具体的,在插入start位置的新节点,即DOM节点;start++。
例:<div>{'a'}{'b'}</div>变为<div><b/></span></div>。遍历第1步略;遍历第2步插入start(1)位置插入span标签;start++为start(2)。
针对T2D状态跳转至T2T,对应预设渲染操作b0,包括:在真实DOM树的当前真实索引位置处插入第二虚拟DOM树中当前虚拟索引位置处的文本节点,创建索引记录,索引记录中的虚拟索引内容记录为第二虚拟DOM树中当前虚拟索引位置处的文本节点的内容,如果第二虚拟DOM树中当前虚拟索引位置处的文本内容与第一虚拟DOM树中当前虚拟索引位置处的文本内容不一致,标记真实DOM树中当前真实索引位置的内容需要更新。
具体的,在start处插入新节点,记录index(1)和start(1)为新VirtualRange的索引,对比老文本和新文本是否相等,不相等的话标记此VirtualRange需要更新。例如:<div>a{'b'}</div>变为<div><span></span>b</div>。遍历第1步文本节点a变为span节点,遍历第2步在start(1)处插入文本节点b,对比之前的文本b发现没有变化,所以无需更新。
针对T2D状态跳转至D2T,对应预设渲染操作c1,包括:将真实DOM树中当前真实索引位置对应的DOM节点变更为第二虚拟DOM树中当前虚拟索引位置处的文本节点,创建索引记录,索引记录中的虚拟索引内容记录为第二虚拟DOM树中当前虚拟索引位置处的文本节点的内容。
具体的,替换start位置的新旧节点,将index和start中变更前的DOM节点对应的索引位置更新为新的变更后的文本节点的内容,记录index和start为新VirtualRange的索引。
例如:<div>a<span></span></div>变为<div><span></span>a</div>。遍历第1步时,文本节点a变为span节点;遍历第2步在start(1)替换span标签为a文本节点,记录当前index(1)和start(1)为新VirtualRange的索引与内容。
针对T2D状态跳转至D2D,对应预设渲染操作b3,包括:如果第二虚拟DOM树中当前虚拟索引位置处的DOM节点与第一虚拟DOM树中当前虚拟索引位置处DOM节点不一致,将真实DOM树中当前真实索引位置对应的DOM节点变更为第二虚拟DOM树中当前虚拟索引位置处的DOM节点,将真实DOM树的当前真实索引位置加1。
具体的,检查第一虚拟DOM树和第二虚拟DOM树中当前虚拟索引位置处的DOM节点是否变更,然后在变更前的DOM节点处进行更新,更新为变更后的DOM节点的内容,start++。
例如:<div>a<span></span></div>变为<div><span></span><b/></div>。遍历第1步时,文本节点a变为了span节点,遍历第2步在start(1)替换span标签为DOM节点b标签,start++为start(2)。
针对初始状态跳转至D2T,对应预设渲染操作f1,包括:将真实DOM树中当前真实索引位置对应的DOM节点变更为第二虚拟DOM树中当前虚拟索引位置处的文本节点,创建索引记录,索引记录中的虚拟索引内容记录为第二虚拟DOM树中当前虚拟索引位置处的文本节点的内容。
具体的,在变更前的DOM节点处进行更新,更新为变更后的文本节点的内容,在此处记录index和start为新VirtualRange的索引。
例如:<div><span></span></div>变为<div>a</div>。遍历第1步,替换span标签为a文本节点,记录index(0)和start(0)为新VirtualRange的索引内容。
针对D2T跳转至D2T,对应预设渲染操作a1,包括:获得当前虚拟索引位置的前一个虚拟索引位置对应的索引记录,如果索引记录中标记真实DOM树当前真实索引位置的内容需要更新,则将真实DOM树中当前真实索引位置更新为索引记录中的虚拟索引内容,移除真实DOM树的当前真实索引位置加1处的节点。
具体的,移除start+1位置的节点,检查之前的VirtualRange更新。
例:<div><span></span>a</div>变为<div>b{'c'}</div>。遍历第1步略;遍历第2步移除start+1(1)位置的a文本节点,检查发现文本空变为bc,更新文本节点内容为bc。
针对D2T跳转至T2T,对应预设渲染操作a0,包括:移除真实DOM树的当前真实索引位置加1处的节点,创建索引记录,索引记录中记录的虚拟索引内容为在第二虚拟DOM树中当前虚拟索引位置处的文本节点的内容与相邻的上一个文本节点对应的索引记录中的虚拟索引内容的合并内容,标记真实DOM树中当前真实索引位置的内容需要更新。
具体的,将D2T中变更前的DOM节点后的文本节点从真实DOM树中删除,即移除start+1位置的节点,对DOM节点前一索引位置处的合并内容VirtualRange进行更新,合并内容包括新的变更后的文本节点的内容。
例如:<div><span></span>a</div>变为<div>b{'c'}</div>。遍历第1步时,span节点变为文本节点b,遍历第2步移除start+1(1)位置的a文本节点,检查发现文本b变为bc,更新文本节点内容为bc。
针对D2T跳转至T2D,对应预设渲染操作a2,包括:将真实DOM树的当前真实索引位置加1,将真实DOM树中当前真实索引位置对应的文本节点变更为第二虚拟DOM树中当前虚拟索引位置处的DOM节点,将真实DOM树的当前真实索引位置加1。
具体的,针对真实DOM树中文本节点索引位置start++,替换该start位置的新旧节点,即:将真实DOM树中当前真实索引位置对应的文本节点变更为第二虚拟DOM树中当前虚拟索引位置处的DOM节点,start++。
例如:<div><span></span>a</div>变为<div>a<span></span></div>。遍历第1步时,span节点变为文本节点a。遍历第2步start++为start(1),替换start(1)位置的文本节点a为span标签,start++为start(2)。
针对D2T状态跳转至D2D状态,对应预设渲染操作c3,包括:将真实DOM树的当前真实索引位置加1,如果第二虚拟DOM树中当前虚拟索引位置处的DOM节点与第一虚拟DOM树中当前虚拟索引位置处的DOM节点不一致,将真实DOM树的当前真实索引位置处的DOM节点更新为第二虚拟DOM树中当前虚拟索引位置处的DOM节点,将真实DOM树的当前真实索引位置加1。
具体的,start++,检查第一虚拟DOM树和第二虚拟DOM树中当前虚拟索引位置处的DOM节点是否变更,如果变更,然后进行更新;start++。
例如:<div><b/><span></span></div>变为<div>a<b/></div>。遍历第1步DOM节点b变为文本节点a,遍历第2步start++为1,发现span标签变为b标签,进行更新替换;start++为start(2)。
针对初始状态跳转至D2D状态,对应预设渲染操作f3,包括:如果第二虚拟DOM树中当前虚拟索引位置处的DOM节点与第一虚拟DOM树中当前虚拟索引位置处DOM节点不一致,将真实DOM树中当前真实索引位置对应的DOM节点变更为第二虚拟DOM树中当前虚拟索引位置处的DOM节点,将真实DOM树的当前真实索引位置加1。
具体的,检查第一虚拟DOM树和第二虚拟DOM树中当前虚拟索引位置处的DOM节点是否变更,如果变更,然后进行更新;start++。
例如:<div><span></span></div>变为<div><b/></div>。遍历第1步,发现span标签变为b标签,替换;start++为1。
针对D2D状态跳转至D2D状态,对应预设渲染操作a3,包括:如果第二虚拟DOM树中当前虚拟索引位置处的DOM节点与第一虚拟DOM树中当前虚拟索引位置处DOM节点不一致,将真实DOM树中当前真实索引位置对应的DOM节点变更为第二虚拟DOM树中当前虚拟索引位置处的DOM节点,将真实DOM树的当前真实索引位置加1。
具体的,检查start位置的新旧节点,如果第二虚拟DOM树中当前虚拟索引位置处的DOM节点与第一虚拟DOM树中当前虚拟索引位置处DOM节点不一致,将真实DOM树中当前真实索引位置对应的DOM节点变更为第二虚拟DOM树中当前虚拟索引位置处的DOM节点;start++。
例:<div><b/><span></span></div>变为<div><span></span><b/></div>。遍历第1步略;遍历第2步在start(1)替换span标签为b标签,start++为start(2)。
针对D2D状态跳转至T2T状态,对应预设渲染操作c0,包括:创建索引记录,索引记录中记录有虚拟索引内容,虚拟索引内容为第二虚拟DOM树中当前虚拟索引位置处的文本内容,如果第二虚拟DOM树中当前虚拟索引位置处的文本内容与第一虚拟DOM树中当前虚拟索引位置处的文本内容不一致,标记真实DOM树中当前真实索引位置的内容需要更新。
具体的,预设渲染操作c0包括记录index和start为新VirtualRange的索引,对比老文本和新文本是否相等,不相等的话标记此VirtualRange需要更新。例如:<div><span></span>a</div>变为<div><span></span>c</div>。遍历第1步时,span节点没有改变;遍历第2步记录index(1)和start(1)为新的VirtualRange,检查更新发现文本a变为c,进行更新。
针对D2D状态跳转至D2T状态,对应预设渲染操作d1,包括:将真实DOM树中当前真实索引位置对应的DOM节点变更为第二虚拟DOM树中当前虚拟索引位置处的文本节点,创建索引记录,索引记录中的虚拟索引内容记录为第二虚拟DOM树中当前虚拟索引位置处的文本节点的内容。
具体的,替换start位置的新旧节点,将index和start中变更前的DOM节点对应的索引位置更新为新的变更后的文本节点的内容,记录index和start为新VirtualRange的索引。
例如:<div><span></span><b/></div>变为<div><span></span>a</div>。遍历第1步时,span节点没有改变;遍历第2步在start(1)替换b标签为a文本节点,记录当前index(1)和start(1)为新VirtualRange的索引。
针对D2D状态跳转至T2D状态,对应预设渲染操作b2,包括:将真实DOM树中当前真实索引位置对应的文本节点变更为第二虚拟DOM树中当前虚拟索引位置处的DOM节点,将真实DOM树的当前真实索引位置加1。
具体的,替换start位置的新旧节点,将index和start中变更前的文本节点对应的索引位置更新为新的变更后的DOM节点的内容。
例如:<div><span></span>a</div>变为<div><span></span><b/></div>。遍历第1步时,span节点没有改变;遍历第2步替换start(1)位置的a文本为DOM节点b标签;start++为start(2)。
针对上述不同状态间转移对应的20种操作,目标页面前后对应的两颗虚拟DOM树对比得到的节点变更信息,然后确定与节点变更信息对应的目标转移状态后,即可按对应的预设渲染操作进行渲染。第一虚拟DOM树中虚拟索引位置0-4位置分别为D1、T1、T2、D2、T4,第二虚拟DOM树中虚拟索引位置0-4位置分别为T5、T6、D5、T3、D3。首先,针对两颗虚拟DOM树,index(0)位置对应的是初始状态至D2T状态,进行f1操作,将真实DOM树中当前真实索引位置start(0)对应的DOM节点D1变更为第二虚拟DOM树中当前虚拟索引位置处的文本节点T5,创建索引记录,索引记录中的虚拟索引内容记录为第二虚拟DOM树中当前虚拟索引位置处的文本节点的内容T5。
进而,对比至index(1)位置,对应D2T状态至T2T状态,进行a0操作,移除真实DOM树的当前真实索引位置加1处的节点,即移除start(1)节点T1+T2,创建索引记录,索引记录中记录的虚拟索引内容为在第二虚拟DOM树中当前虚拟索引位置处的文本节点的内容T6与相邻的上一个文本节点对应的索引记录中的虚拟索引内容T5的合并内容T5+T6,标记start(0)需要更新。
进而,对比至index(2)位置,对应T2T状态至T2D状态,进行d2操作,获得当前虚拟索引位置的前一个虚拟索引位置对应的索引记录,如果索引记录中标记真实DOM树当前真实索引位置的内容需要更新,由于前述中标记start(0)需要更新,则将真实DOM树中当前真实索引位置start(0)处的文本节点内容变更为索引记录中的虚拟索引内容T5+T6,将真实DOM树的当前真实索引位置加1变为start(1),将第二虚拟DOM树中的当前虚拟索引位置处的DOM节点D5插入真实DOM树的当前真实索引位置start(1)处,start(1)就为D5,将真实DOM树的当前真实索引位置加1变为start(2)。
进而,对比至index(3)位置,对应T2D状态至D2T状态,进行c1操作,将真实DOM树中当前真实索引位置start(2)对应的DOM节点D2变更为第二虚拟DOM树中当前虚拟索引位置处的文本节点T3,创建索引记录,索引记录中的虚拟索引内容记录为第二虚拟DOM树中当前虚拟索引位置处的文本节点的内容T3。
进而,对比至index(4)位置,对应D2T状态至T2D状态,进行a2操作,将真实DOM树的当前真实索引位置加1得start(3),将真实DOM树中当前真实索引位置start(3)对应的文本节点T4变更为第二虚拟DOM树中当前虚拟索引位置处的DOM节点D3,将真实DOM树的当前真实索引位置加1为start(4)。后续节点,可按照上述示例中的方式依次进行对比更新,在此申请人不再赘述。
所以,本实施例中的方案,在检测到目标页面中存在数据变更情况下,获得与变更前的视图页面的第一虚拟DOM树以及变更后的视图页面的第二虚拟DOM树,然后按虚拟索引位置依次进行对比,根据对比结果,按真实索引位置依次对真实DOM树中对应节点进行渲染操作,直至对比至最后一个虚拟索引位置。由于预先构建了预设状态转移图,该状态转移图中,包含了页面渲染时所有的状态转移关系,针对每一种状态转移关系,预先配置了与之对应的预设渲染操作。所以,每次比对时,可以从预设状态转移图中确定出相邻的两个虚拟索引位置处节点的状态转移关系,然后按与该状态转移关系对应的渲染操作进行页面渲染,使得文本数据不再需要被SPAN或注释等其它标签包裹,从而达到无侵入原有DOM结构、不增加多余数据、不触发多余变更事件的效果。
第二方面,基于同一发明构思,本说明书实施例提供一种局部页面动态渲染装置,请参考图3,包括:
获取单元301,用于在检测到目标页面中存在数据变更情况下,获得与变更前的视图页面的第一虚拟DOM树以及变更后的视图页面的第二虚拟DOM树,其中,针对所述虚拟DOM树和所述第二虚拟DOM树创建有同一虚拟索引,针对真实DOM树创建有真实索引;
渲染单元302,用于按虚拟索引顺序依次对所述第一虚拟DOM树中节点与所述第二虚拟DOM树中的节点进行对比,确定所述第一虚拟DOM树和所述第二虚拟DOM树中在当前虚拟索引位置处的节点的第一变更状态,以及确定所述第一虚拟DOM树和所述第二虚拟DOM树中在前一虚拟索引位置处的节点的第二变更状态,根据相邻两个虚拟索引位置处节点的变更状态与预设渲染操作间预设的对应关系,确定与所述第二变更状态至所述第一变更状态对应的目标预设渲染操作,按所述目标预设渲染操作对所述真实DOM树中对应真实索引位置处的节点进行渲染,直至完成最后一个虚拟索引位置所对应的真实索引位置处的节点的渲染。
在一种可选的实现方式中,所述装置还包括处理单元,所述处理单元具体用于:
在对所述目标页面初始化渲染后,获得初始页面的初始虚拟DOM树;
遍历所述初始虚拟DOM树,确定所述初始虚拟DOM树中所包含的空白变量;
在每个所述空白变量位置处插入空文本节点。
在一种可选的实现方式中,所述空白变量包括空字符串、null字段、空数组和undefined字段中的任意一种。
在一种可选的实现方式中,所述渲染单元具体用于:
如果所述第二变更状态至所述第一变更状态为所述初始状态跳转至所述文本节点至文本节点变更状态或所述DOM节点至DOM节点变更状态跳转至所述文本节点至文本节点变更状态,创建索引记录,所述索引记录中记录有虚拟索引内容,虚拟索引内容为所述第二虚拟DOM树中当前虚拟索引位置处的文本内容,如果所述第二虚拟DOM树中当前虚拟索引位置处的文本内容与所述第一虚拟DOM树中当前虚拟索引位置处的文本内容不一致,标记所述真实DOM树中当前真实索引位置的内容需要更新。
在一种可选的实现方式中,所述渲染单元具体用于:
如果所述第二变更状态至所述第一变更状态为所述文本节点至文本节点变更状态跳转至所述文本节点至文本节点变更状态,创建索引记录,所述索引记录中记录的虚拟索引内容为在所述第二虚拟DOM树中当前虚拟索引位置处的文本节点的内容与相邻的上一个文本节点对应的索引记录中的虚拟索引内容的第一合并内容,确定在所述第一虚拟DOM树中包括所述当前虚拟索引位置处的节点在内的前面连续的文本节点对应的第二合并内容,如果所述第一合并内容和所述第二合并内容不一致,标记所述真实DOM树当前真实索引位置的内容需要更新。
在一种可选的实现方式中,所述渲染单元具体用于:
如果所述第二变更状态至所述第一变更状态为所述文本节点至文本节点变更状态跳转至所述文本节点至DOM节点变更状态,获得所述当前虚拟索引位置的前一个虚拟索引位置对应的索引记录,如果所述索引记录中标记所述真实DOM树当前真实索引位置的内容需要更新,则将所述真实DOM树中当前真实索引位置处的文本节点内容变更为所述索引记录中的虚拟索引内容,将所述真实DOM树的当前真实索引位置加1,将所述第二虚拟DOM树中的所述当前虚拟索引位置处的DOM节点插入所述真实DOM树的当前真实索引位置,将所述真实DOM树的当前真实索引位置加1。
在一种可选的实现方式中,所述渲染单元具体用于:
如果所述第二变更状态至所述第一变更状态为所述文本节点至文本节点变更状态跳转至所述DOM节点至文本节点变更状态,获得所述当前虚拟索引位置的前一虚拟索引位置对应的索引记录,如果所述索引记录中标记所述真实DOM树当前真实索引位置的内容需要更新,则将所述真实DOM树中当前真实索引位置处的文本节点的内容变更为所述索引记录中的虚拟索引内容,移除所述真实DOM树的当前真实索引位置加1处的节点。
在一种可选的实现方式中,所述渲染单元具体用于:
如果所述第二变更状态至所述第一变更状态为所述文本节点至文本节点变更状态跳转至所述DOM节点至DOM节点变更状态或所述DOM节点至文本节点变更状态跳转至所述DOM节点至文本节点变更状态,将所述真实DOM树的当前真实索引位置加1,如果所述第二虚拟DOM树中当前虚拟索引位置处的DOM节点与所述第一虚拟DOM树中当前虚拟索引位置处的DOM节点不一致,将所述真实DOM树的当前真实索引位置处的DOM节点更新为所述第二虚拟DOM树中当前虚拟索引位置处的DOM节点,将所述真实DOM树的当前真实索引位置加1。
在一种可选的实现方式中,所述渲染单元具体用于:
如果所述第二变更状态至所述第一变更状态为所述初始状态跳转至所述文本节点至DOM节点变更状态或所述DOM节点至DOM节点变更状态跳转至所述文本节点至DOM节点变更状态,将所述真实DOM树中当前真实索引位置对应的文本节点变更为所述第二虚拟DOM树中当前虚拟索引位置处的DOM节点,将所述真实DOM树的当前真实索引位置加1。
在一种可选的实现方式中,所述渲染单元具体用于:
如果所述第二变更状态至所述第一变更状态为所述文本节点至DOM节点变更状态跳转至所述文本节点至DOM节点变更状态,在所述真实DOM树的当前真实索引位置处插入所述第二虚拟DOM树中当前虚拟索引位置处的DOM节点,将所述真实DOM树的当前真实索引位置加1。
在一种可选的实现方式中,所述渲染单元具体用于:
如果所述第二变更状态至所述第一变更状态为所述文本节点至DOM节点变更状态跳转至所述文本节点至文本节点变更状态,在所述真实DOM树的当前真实索引位置处插入所述第二虚拟DOM树中当前虚拟索引位置处的文本节点,创建索引记录,所述索引记录中的虚拟索引内容记录为第二虚拟DOM树中当前虚拟索引位置处的文本节点的内容,如果所述第二虚拟DOM树中当前虚拟索引位置处的文本内容与所述第一虚拟DOM树中当前虚拟索引位置处的文本内容不一致,标记所述真实DOM树中当前真实索引位置的内容需要更新。
在一种可选的实现方式中,所述渲染单元具体用于:
如果所述第二变更状态至所述第一变更状态为所述文本节点至DOM节点变更状态跳转至所述DOM节点至文本节点变更状态或所述第二变更状态至所述第一变更状态为所述初始状态变更状态跳转至所述DOM节点至文本节点变更状态或所述DOM节点至DOM节点变更状态跳转至所述DOM节点至文本节点变更状态,将所述真实DOM树中当前真实索引位置对应的DOM节点变更为所述第二虚拟DOM树中当前虚拟索引位置处的文本节点,创建索引记录,所述索引记录中的虚拟索引内容记录为所述第二虚拟DOM树中当前虚拟索引位置处的文本节点的内容。
在一种可选的实现方式中,所述渲染单元具体用于:
如果所述第二变更状态至所述第一变更状态为所述文本节点至DOM节点变更状态跳转至所述DOM节点至DOM节点变更状态或所述初始状态跳转至所述DOM节点至DOM节点变更状态或所述DOM节点至DOM节点变更状态跳转至所述DOM节点至DOM节点变更状态,如果所述第二虚拟DOM树中当前虚拟索引位置处的DOM节点与所述第一虚拟DOM树中当前虚拟索引位置处DOM节点不一致,将所述真实DOM树中当前真实索引位置对应的DOM节点变更为所述第二虚拟DOM树中当前虚拟索引位置处的DOM节点,将所述真实DOM树的当前真实索引位置加1。
在一种可选的实现方式中,所述渲染单元具体用于:
如果所述第二变更状态至所述第一变更状态为所述文本节点至DOM节点变更状态跳转至所述DOM节点至文本节点变更状态,获得所述当前虚拟索引位置的前一个虚拟索引位置对应的索引记录,如果所述索引记录中标记所述真实DOM树当前真实索引位置的内容需要更新,则将所述真实DOM树中当前真实索引位置更新为所述索引记录中的虚拟索引内容,移除所述真实DOM树的当前真实索引位置加1处的节点。
在一种可选的实现方式中,所述渲染单元具体用于:
如果所述第二变更状态至所述第一变更状态为所述文本节点至DOM节点变更状态跳转至所述文本节点至文本节点变更状态,移除所述真实DOM树的当前真实索引位置加1处的节点,创建索引记录,所述索引记录中记录的虚拟索引内容为在所述第二虚拟DOM树中当前虚拟索引位置处的文本节点的内容与相邻的上一个文本节点对应的索引记录中的虚拟索引内容的合并内容,标记所述真实DOM树中当前真实索引位置的内容需要更新。
在一种可选的实现方式中,所述渲染单元具体用于:
如果所述第二变更状态至所述第一变更状态为所述文本节点至DOM节点变更状态跳转至所述文本节点至DOM节点变更状态,将所述真实DOM树的当前真实索引位置加1,将所述真实DOM树中当前真实索引位置对应的文本节点变更为所述第二虚拟DOM树中当前虚拟索引位置处的DOM节点,将所述真实DOM树的当前真实索引位置加1。
第三方面,基于与前述实施例中局部页面动态渲染方法同样的发明构思,本发明还提供一种局部页面动态渲染装置,如图4所示,包括存储器704、处理器702及存储在存储器704上并可在处理器702上运行的计算机程序,所述处理器702执行所述程序时实现前文所述局部页面动态渲染方法的任一方法的步骤。
其中,在图4中,总线架构(用总线700来代表),总线700可以包括任意数量的互联的总线和桥,总线700将包括由处理器702代表的一个或多个处理器和存储器704代表的存储器的各种电路链接在一起。总线700还可以将诸如外围设备、稳压器和功率管理电路等之类的各种其他电路链接在一起,这些都是本领域所公知的,因此,本文不再对其进行进一步描述。总线接口706在总线700和接收器701和发送器703之间提供接口。接收器701和发送器703可以是同一个元件,即收发机,提供用于在传输介质上与各种其他装置通信的单元。处理器702负责管理总线700和通常的处理,而存储器704可以被用于存储处理器702在执行操作时所使用的数据。
第四方面,基于与前述实施例中局部页面动态渲染的发明构思,本发明还提供一种计算机可读存储介质,其上存储有计算机程序,该程序被处理器执行时实现前文所述局部页面动态渲染的方法的任一方法的步骤。
本说明书是参照根据本说明书实施例的方法、设备(系统)、和计算机程序产品的流程图和/或方框图来描述的。应理解可由计算机程序指令实现流程图和/或方框图中的每一流程和/或方框、以及流程图和/或方框图中的流程和/或方框的结合。可提供这些计算机程序指令到通用计算机、专用计算机、嵌入式处理机或其他可编程数据处理设备的处理器以产生一个机器,使得通过计算机或其他可编程数据处理设备的处理器执行的指令产生用于实现在流程图一个流程或多个流程和/或方框图一个方框或多个方框中指定的功能的设备。
这些计算机程序指令也可存储在能引导计算机或其他可编程数据处理设备以特定方式工作的计算机可读存储器中,使得存储在该计算机可读存储器中的指令产生包括指令设备的制造品,该指令设备实现在流程图一个流程或多个流程和/或方框图一个方框或多个方框中指定的功能。
这些计算机程序指令也可装载到计算机或其他可编程数据处理设备上,使得在计算机或其他可编程设备上执行一系列操作步骤以产生计算机实现的处理,从而在计算机或其他可编程设备上执行的指令提供用于实现在流程图一个流程或多个流程和/或方框图一个方框或多个方框中指定的功能的步骤。
尽管已描述了本说明书的优选实施例,但本领域内的技术人员一旦得知了基本创造性概念,则可对这些实施例作出另外的变更和修改。所以,所附权利要求意欲解释为包括优选实施例以及落入本说明书范围的所有变更和修改。
显然,本领域的技术人员可以对本说明书进行各种改动和变型而不脱离本说明书的精神和范围。这样,倘若本说明书的这些修改和变型属于本说明书权利要求及其等同技术的范围之内,则本说明书也意图包含这些改动和变型在内。