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 相关文章推荐
多广告投放代码 推荐
Nov 13 Javascript
jquery获取input的value问题说明
Aug 19 Javascript
jQuery+css实现的tab切换标签(兼容各浏览器)
Jan 28 Javascript
Angular工具方法学习
Dec 26 Javascript
整理关于Bootstrap模态弹出框的慕课笔记
Mar 29 Javascript
vue将对象新增的属性添加到检测序列的方法
Feb 24 Javascript
Vue前端开发规范整理(推荐)
Apr 23 Javascript
layui使用label标签的方法
Sep 14 Javascript
vue学习笔记之作用域插槽实例分析
Feb 01 Javascript
vue 检测用户上传图片宽高的方法
Feb 06 Javascript
js绘制一条直线并旋转45度
Aug 21 Javascript
JavaScript常用进制转换及位运算实例解析
Oct 14 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
destoon实现首页显示供应、企业、资讯条数的方法
2014/07/15 PHP
PHP实现的折半查找算法示例
2017/12/19 PHP
Javascript 作用域使用说明
2009/08/13 Javascript
JavaScript表单通过正则表达式验证电话号码
2014/03/14 Javascript
NodeJS制作爬虫全过程
2014/12/22 NodeJs
javascript中DOM复选框选择用法实例
2015/05/14 Javascript
js替换字符串中所有指定的字符(实现代码)
2016/08/17 Javascript
zTree获取当前节点的下一级子节点数实例
2017/09/05 Javascript
React Native 通告消息竖向轮播组件的封装
2020/08/25 Javascript
Element-UI Table组件上添加列拖拽效果实现方法
2018/04/14 Javascript
实例分析编写vue组件方法
2019/02/12 Javascript
详解微信小程序-扫一扫 wx.scanCode() 扫码大变身
2019/04/30 Javascript
selenium 反爬虫之跳过淘宝滑块验证功能的实现代码
2020/08/27 Javascript
Python编程对列表中字典元素进行排序的方法详解
2017/05/26 Python
Python实现Kmeans聚类算法
2020/06/10 Python
python pandas中DataFrame类型数据操作函数的方法
2018/04/08 Python
Python中的函数作用域
2018/05/07 Python
pyttsx3实现中文文字转语音的方法
2018/12/24 Python
详解python运行三种方式
2019/05/13 Python
关于numpy数组轴的使用详解
2019/12/05 Python
python实现全排列代码(回溯、深度优先搜索)
2020/02/26 Python
python GUI库图形界面开发之PyQt5日期时间控件QDateTimeEdit详细使用方法与实例
2020/02/27 Python
eDreams澳大利亚:预订机票、酒店和度假产品
2017/04/19 全球购物
网络工程师的自我评价
2013/10/02 职场文书
军校制空专业毕业生自我鉴定
2013/11/16 职场文书
销售辞职报告范文
2014/01/12 职场文书
会走路的树教学反思
2014/02/20 职场文书
中介公司区域经理岗位职责范本
2014/03/02 职场文书
会计核算科岗位职责
2014/03/19 职场文书
初三学生个人自我评定
2014/04/06 职场文书
住院医师规范化培训实施方案
2014/06/12 职场文书
职代会闭幕词
2015/01/28 职场文书
毕业论文答辩演讲稿
2015/06/23 职场文书
Python中for后接else的语法使用
2021/05/18 Python
Python3 类型标注支持操作
2021/06/02 Python
使用Python开发贪吃蛇游戏 SnakeGame
2022/04/30 Python