Vue中fragment.js使用方法小结


Posted in Javascript onFebruary 17, 2020

createDocumentFragment

如果要在一个节点上一次性插入多个元素怎么办,比如说一次插入 10000 个节点?

最简单粗暴的方式就是:

var parent = document.getElementById(`'parent'`);

for`(`var i = 0; i < 10000; i++) {

var child = document.createElement(`'div'`);

var text = document.createTextNode(`'' + i);`

child.appendChild(text);

parent.appendChild(child);

}

不过众所周知的原因,对 DOM 反复操作会导致页面重绘、回流,效率非常低,而且页面可能会被卡死,这段代码基本是没人用的。

如果分段来进行 DOM 操作呢,这样就能避免卡死页面了,js 忍者秘籍里面提到过可以用 setTimeout 来改进:

var i = 0, max = 10000;

setTimeout(`function addNodes() {`

for`(`var step = i + 500; i < step; i++) {

var child = document.createElement(`'div'`);

child.appendChild(document.createTextNode(`'' + i));`

div.appendChild(child);

}

if`(i < max) {`

setTimeout(addNodes, 0);

}

}, 0);

当然,更多能想到的方式应该是,在内存中直接操作节点,所有节点都凑在一起之后再跟 DOM 树进行交互,把所有节点都串在一个 div 上,然后再把 div 挂到 DOM 树上:

var parent = document.getElementById(`'parent'`);

var div = document.createElement(`'div'`);

for`(`var i = 0; i < 10000; i++) {

var child = document.createElement(`'div'`);

var text = document.createTextNode(`'' + i);`

child.appendChild(text);

div.appendChild(child);

}

parent.appendChild(div);

如上,只跟 DOM 树交互一次,性能方面肯定是大有改善的,不过额外插入了一个 div,如果说不是跟div之类的节点进行交互呢,比如在 table 中插入 th、td?

这时候,createDocumentFragment 就该出马了,翻译过来叫“文档片段”,按MDN的描述:

DocumentFragments 是一些 DOM 节点。它们不是 DOM 树的一部分。通常的使用场景是创建一个文档片段,然后将创建的 DOM 元素插入到文档片段中,最后把文档片段插入到 DOM 树中。在 DOM 树中,文档片段会被替换为它所有的子元素。

因为文档片段存在与内存中,并不在 DOM 树中,所以将子元素插入到文档片段时不会引起页面回流(对元素位置和几何上的计算)。因此,使用文档片段 document fragments 通常会起到优化性能的作用。

简单来说,就是上面一个例子的不需要 div 中转版本,插入的时候,直接用其子元素替换其本身,非常完美。

虽然说,“好用的都不通用”(特别是针对某公司浏览器),不过这个好用的东西,甚至连 IE6 都支持。

具体代码大概就长这样:

var parent = document.getElementById(`'parent'`);

var frag = document.createDocumentFragment();

for`(`var i = 0; i < 10000; i++) {

var child = document.createElement(`'div'`);

var text = document.createTextNode(`'' + i);`

child.appendChild(text);

frag.appendChild(child);

}

parent.appendChild(frag);

具体性能方面的测试,有兴趣的可以把所有代码都跑一遍。

innerHTML

把一长串字符串转换为对应的 DOM 节点,正常而言,首先想到的肯定是 innerHTML。大概流程就是,先创建一个 div 节点,然后 div.innerHTML = str,根据需要把 div 的 children 取出来放到该放的地方去,div 本身给扔了。

如果想单独生成一个 th 节点呢?

试试上面的流程:

var div = document.createElement(`'div'`);

div.innerHTML = '<th>xxx</th>'`;`

console.log(div);

实际输出是(chrome 下):

<`div>xxx</div`>

并没有得到想要的:

<`div><th>xxx</th></div`>

对于这样的结果是可以理解的,毕竟一个 th 放到 div 里面,怎么看都不对,直接把外围的标签去掉,内容扔到 div 里面也是相当智能的。

不过架不住,有时候就是要获取一个 th 节点。

其实也好办,写全了不就得了:

var node = document.createElement(`'div'`);

node.innerHTML = '<table><tbody><tr><th>xxx</th></tr></tbody></table>'`;`

// 把外面的几层皮扒掉就是想要的 th 了

var depth = 3;

while`(depth--) {`

node = node.lastChild;

}

console.log(node.firstChild);

可以看出,结果正是所想要的。

fragment.js

// 需要单独处理的一些特殊节点
var map = {
 legend : [1, '<fieldset>', '</fieldset>'],
 tr : [2, '<table><tbody>', '</tbody></table>'],
 col : [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'],
 
 _default : [0, '', '']
};
map.td = map.th = [3, '<table><tbody><tr>', '</tr></tbody></table>'];
map.option = map.optgroup = [1, '<select multiple="multiple">', '</select>'];
map.thead = map.tbody = map.colgroup = map.caption = map.tfoot = [1, '<table>', '</table>']
map.text = map.circle = map.ellipse = map.line = map.path = map.polygon = map.polyline = map.rect = [1, '<svg xmlns="http://www.w3.org/2000/svg" version="1.1">','</svg>'];
 
var TAG_RE = /<([\w:]+)/;
 
module.exports = function(templateString) {
 var frag = document.createDocumentFragment(),
 m = TAG_RE.exec(templateString);
 // 单纯字符串的情况
 if(!m) {
 frag.appendChild(document.createTextNode(templateString);
 return frag;
 }
 
 var tag = m[1],
 wrap = map[tag] || map._default,
 depth = wrap[0],
 prefix = wrap[1],
 suffix = wrap[2],
 node = document.createElement('div');
 // 拼接节点字符串
 node.innerHTML = prefix + templateString.trim() + suffix;
 // 去除外包裹层,只留字符串转化的节点
 while(depth--) node = node.lastChild;
 // 只有一个节点的情况
 if(node.firstChild === node.lastChild) { 
 frag.appendChild(node.firstChild);
 return frag;
 }
 // 多个节点,依序添加到 frag
 var child;
 while(child = node.firstChild) {
 frag.appendChild(child);
 }
 return frag;
}
Javascript 相关文章推荐
JavaScript调用Activex控件的事件的实现方法
Apr 11 Javascript
js去空格技巧分别去字符串前后、左右空格
Oct 21 Javascript
javascript使用Promise对象实现异步编程
Mar 01 Javascript
浅谈jquery选择器 :first与:first-child的区别
Nov 20 Javascript
jQuery validate 验证radio实例
Mar 01 Javascript
BootStrap的双日历时间控件使用
Jul 25 Javascript
利用nvm管理多个版本的node.js与npm详解
Nov 02 Javascript
vue.js-div滚动条隐藏但有滚动效果的实现方法
Mar 03 Javascript
JavaScript引用类型RegExp基本用法详解
Aug 09 Javascript
微信小程序使用wxParse解析html的实现示例
Aug 30 Javascript
深入解析ES6中的promise
Nov 08 Javascript
vue 使用axios 数据请求第三方插件的使用教程详解
Jul 05 Javascript
javascript实现倒计时效果
Feb 17 #Javascript
JavaScript将数组转换为链表的方法
Feb 16 #Javascript
javascript canvas API内容整理
Feb 16 #Javascript
vue props 单项数据流实例分享
Feb 16 #Javascript
卸载vue2.0并升级vue_cli3.0的实例讲解
Feb 16 #Javascript
vue中axios防止多次触发终止多次请求的示例代码(防抖)
Feb 16 #Javascript
Vue简单封装axios之解决post请求后端接收不到参数问题
Feb 16 #Javascript
You might like
用PHP将网址字符串转换成超链接(网址或email)
2010/05/25 PHP
php实现使用正则将文本中的网址转换成链接标签
2014/12/03 PHP
写一段简单的PHP建立文件夹代码
2015/01/06 PHP
session 加入redis的实现代码
2016/07/15 PHP
CL vs ForZe BO5 第五场 2.13
2021/03/10 DOTA
Javascript 获取链接(url)参数的方法
2009/02/15 Javascript
jquery等宽输出文字插件使用介绍
2013/09/18 Javascript
javascript实现的平方米、亩、公顷单位换算小程序
2014/08/11 Javascript
jquery实现侧边弹出的垂直导航
2014/12/09 Javascript
js判断鼠标左、中、右键哪个被点击的方法
2015/01/27 Javascript
jQuery+JSON实现AJAX二级联动实例分析
2015/12/18 Javascript
JavaScript数据结构之数组的表示方法示例
2017/04/12 Javascript
nodejs操作mysql实现增删改查的实例
2017/05/28 NodeJs
微信小程序图片宽100%显示并且不变形
2017/06/21 Javascript
JS倒计时实例_天时分秒
2017/08/22 Javascript
Vue0.1的过滤代码如何添加到Vue2.0直接使用
2017/08/23 Javascript
vue axios 在页面切换时中断请求方法 ajax
2018/03/05 Javascript
从零开始用electron手撸一个截屏工具的示例代码
2018/10/10 Javascript
写一个Vue loading 插件
2020/11/09 Javascript
[03:43]TI9战队采访——PSG.LGD
2019/08/22 DOTA
Python脚本实现集群检测和管理功能
2015/03/06 Python
从CentOS安装完成到生成词云python的实例
2017/12/01 Python
Python实现采用进度条实时显示处理进度的方法
2017/12/19 Python
Python字节单位转换实例
2019/12/05 Python
简单了解python filter、map、reduce的区别
2020/01/14 Python
django项目中新增app的2种实现方法
2020/04/01 Python
Python命名空间namespace及作用域原理解析
2020/06/05 Python
python如何运行js语句
2020/09/09 Python
html5的新玩法——语音搜索
2013/01/03 HTML / CSS
五一服装活动方案
2014/01/11 职场文书
工厂会计员职责
2014/02/06 职场文书
预备党员公开承诺书
2014/05/28 职场文书
机械设计专业大学生职业生涯规划书范文
2014/09/13 职场文书
2014年项目经理工作总结
2014/11/24 职场文书
浅谈sql_@SelectProvider及使用注意说明
2021/08/04 Java/Android
nginx从安装到配置详细说明(安装,安全配置,防盗链,动静分离,配置 HTTPS,性能优化)
2022/02/12 Servers