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 相关文章推荐
新浪的图片新闻效果
Jan 13 Javascript
颜色选择器 Color Picker,IE,Firefox,Opera,Safar
Nov 25 Javascript
Js-$.extend扩展方法使方法参数更灵活
Jan 15 Javascript
浅析tr的隐藏和显示问题
Mar 05 Javascript
jquery实现可旋转可拖拽的文字效果代码
Jan 27 Javascript
js实现5秒倒计时重新发送短信功能
Feb 05 Javascript
微信小程序 动态绑定数据及动态事件处理
Mar 14 Javascript
Vue计算属性的使用
Aug 04 Javascript
node错误处理与日志记录的实现
Dec 24 Javascript
vue中的mescroll搜索运用及各种填坑处理
Oct 30 Javascript
在vue-cli中引入lodash.js并使用详解
Nov 13 Javascript
JS实现动态倒计时功能(天数、时、分、秒)
Dec 12 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
Yii2框架dropDownList下拉菜单用法实例分析
2016/07/18 PHP
Yii2 中实现单点登录的方法
2018/03/09 PHP
jquery+json实现的搜索加分页效果
2010/03/31 Javascript
jquery中动态效果小结
2010/12/16 Javascript
《JavaScript高级程序设计》阅读笔记(三) ECMAScript中的引用类型
2012/02/27 Javascript
jQuery 获取和设置select下拉框的值实现代码
2013/11/08 Javascript
jquery中$(#form :input)与$(#form input)的区别
2014/08/18 Javascript
采用自执行的匿名函数解决for循环使用闭包的问题
2014/09/11 Javascript
javascript实现限制上传文件大小
2015/02/06 Javascript
漫谈JS引擎的运行机制 你应该知道什么
2016/06/15 Javascript
jQuery基于函数重载实现自定义Alert函数样式的方法
2016/07/27 Javascript
详解jQuery lazyload 懒加载
2016/12/19 Javascript
Angularjs使用ng-repeat中$even和$odd属性的注意事项
2016/12/31 Javascript
flag和jq on 的绑定多个对象和方法(必看)
2017/02/27 Javascript
JS动态添加元素及绑定事件造成程序重复执行解决
2017/12/07 Javascript
jQuery实现的鼠标响应缓冲动画效果示例
2018/02/13 jQuery
vue 利用路由守卫判断是否登录的方法
2018/09/29 Javascript
Vue项目自动转换 px 为 rem的实现方法
2018/10/29 Javascript
vue-cli3配置与跨域处理方法
2019/08/17 Javascript
layui使用form表单实现post请求页面跳转的方法
2019/09/14 Javascript
解决antd Form 表单校验方法无响应的问题
2020/10/27 Javascript
[01:22:19]EG vs TNC Supermajor小组赛B组败者组第一轮 BO3 第二场 6.2
2018/06/03 DOTA
[01:03:50]DOTA2-DPC中国联赛 正赛 CDEC vs DLG BO3 第二场 2月7日
2021/03/11 DOTA
python中requests模块的使用方法
2015/04/08 Python
python的exec、eval使用分析
2017/12/11 Python
Django之Mode的外键自关联和引用未定义的Model方法
2018/12/15 Python
python主线程与子线程的结束顺序实例解析
2019/12/17 Python
如何利用python生成MD5并去重
2020/12/07 Python
装上这 14 个插件后,PyCharm 真的是无敌的存在
2021/01/11 Python
银行实习鉴定
2013/12/13 职场文书
公证书标准格式
2014/04/10 职场文书
优秀毕业生就业推荐信
2014/05/22 职场文书
优秀班主任材料
2014/12/16 职场文书
教师聘用意向书
2015/05/11 职场文书
2015年初一班主任工作总结
2015/05/13 职场文书
MySQL里面的子查询的基本使用
2021/08/02 MySQL