前言
感谢国家,这个月开始减税了,工资马上要多些啦。国庆回来的第一天,财务姐姐过来求助公积金的网站打不开,让我帮忙看下。浏览器是IE9,控制台报错:对象不支持“createContextualFragment”属性或方法。createContextualFragment是操作DocumentFragment的方法之一,返回一个DocumentFragment对象。古董浏览器(IE6-IE9)兼容性差,更换浏览器即可解决问题。又继续查了一下资料,可能是触发了EXT框架的一个bug,可插入以下pollyfill解决:
if ((typeof Range !== "undefined") && !Range.prototype.createContextualFragment) {
Range.prototype.createContextualFragment = function(html)
{
var frag = document.createDocumentFragment(),
div = document.createElement("div");
frag.appendChild(div);
div.outerHTML = html;
return frag;
};
}
简介
DocumentFragment,文档片段,用于暂时储存一个或多个邻接的Document节点和它们的所有子孙节点,再统一插入到DOM树中。由于DocumentFragment不是真实DOM,修改DocumentFragment不会触发reflow(回流),仅在把DocumentFragment插入页面时触发一次reflow,提升渲染效率。
DocumentFragment也可用于文档的剪切、复制和粘贴,操作方便。
使用方法
创建:Document.createDocumentFragment()
//创建DocumentFragment
var fragment = document.createDocumentFragment();
//往DocumentFragment中写入内容
var browsers = ['Firefox', 'Chrome', 'Opera',
'Safari', 'Internet Explorer'];
browsers.forEach(function(browser) {
var li = document.createElement('li');
li.textContent = browser;
fragment.appendChild(li);
});
//把DocumentFragment插入页面中
document.body.appendChild(fragment);
//创建一个Range
var range = document.createRange();
//选择需要剪切的内容
range.selectNode(document.getElementsByTagName("div").item(0));
//剪切的内容会在原文档中被删除,返回一个DocumentFragment对象
var documentFragment = range.extractContents();
//把剪切的内容插入到页面中
document.body.appendChild(documentFragment);
//创建一个Range
var range = document.createRange();
//选择需要复制的内容
range.selectNode(document.getElementsByTagName("div").item(0));
//复制的内容会在原文档中保留,也会返回一个DocumentFragment对象
var documentFragment = range.cloneContents();
//把复制的内容插入到页面中
document.body.appendChild(documentFragment);
性能对比
往页面里插入新的新的DOM,或者修改原有DOM的占位空间,都会触发reflow。因此我们构造一下大量插入div,并改变高度的操作:
// 循环次数
const cycle = 100000;
// 使用DocumentFragment
let fragment = document.createDocumentFragment();
for (let i=1; i<=cycle; i++) {
let div = document.createElement("div");
let text =document.createTextNode(`div${i}`);
div.appendChild(text);
div.style.height="30px";
fragment.appendChild(div);
}
document.body.appendChild(fragment);
// 不使用DocumentFragment
for (let i=1; i<=cycle; i++) {
let div = document.createElement("div");
let text =document.createTextNode(`div${i}`);
div.appendChild(text);
div.style.height="30px";
document.body.appendChild(div);
}
分别执行上述两段代码,使用Chrome的performance面板记录页面渲染时间。结果如下图:
可以看到,使用DocumentFragment可以有效减少渲染页面的时间,尤其是Rendering的时间。
总结
DocumentFragment可以储存若干节点,再一次性插入DOM树中,减少页面渲染时间。
听上去虽然不错,但古董浏览器兼容性不佳,而现代浏览器的内部优化,使得DocumentFragment的性能优势并不明显。现今的主流前端框架使用Virtual
DOM(虚拟dom),DocumentFragment能发挥的场景已经不多了。
只有在需要剪切或复制大段内容的时候,才推荐使用它,其余情况下并不推荐使用。
本文未经许可禁止转载,如需转载关注微信公众号【工程师加一】并留言。