DOM片段的学习

826 阅读1分钟

createDocumentFragment()用法总结

定义

createDocumentFragment()方法,是用来创建一个虚拟的节点对象,或者说用来创建文档碎片节点。可以包含各种类型的节点,在创建之初是空的。

使用场景

DocumentFragment节点不属于文档树,继承的parentNode属性总是null。它有一个很实用的特点,当请求把一个DocumentFragment节点插入文档树时,插入的不是DocumentFragment本身,而是它的所有子孙节点,即插入的是括号里的节点。它还有利于实现文档的剪切、复制和粘贴操作

另外,当需要添加多个dom元素时,如果先将这些元素添加到DocumentFragment中,再统一将DocumentFragment添加到页面,会减少页面渲染dom的次数,效率会明显提升。

appendChild

如果使用appendChild方法将原dom树中的节点添加到DocumentFragment中时,会删除原来的节点。

createDocumentFragment()和createElement()的区别:

1. 需要很多的插入操作和改动,继续使用类似于下面的代码则会很有问题

var ul = document.getElementById("ul");
for (var i = 0; i < 20; i++) {
    var li = document.createElement("li");
    li.innerHTML = "index: " + i;
    ul.appendChild(li);
}

由于每一次对文档的插入都会引起重新渲染(计算元素的尺寸、背景显示、内容等),所以进行多次插入操作使得浏览器发生了很多此渲染,效率较低。这时我们提倡通过减少页面的渲染来提高DOM操作的效率的原因。一个优化的方法是将要创建的元素写到一个字符串上,然后一次性写到innerHTML上,这种利用浏览器对innerHTML的解析确实是相对上面的多次插入快了很多,但是构造字符串灵活性比较差,很难符合创建各种各样的DOM元素的需求,利用DocumentFragment可以弥补这两个不足

因为文档片段存在内存中,并不在DOM中,所以将子元素插入到文档片段中是不会引起页面回流(对元素位置和几何上的计算),因此使用DocumentFragment可以起到性能优化的作用。例如上面的代码就可以改成下面的片段

var ul = document.getElementById("ul");
var fragment = document.createDocumentFragment();
for (var i = 0; i < 20; i ++ ) {
	var li = document.createElement("li");
    li.innerHTML = "index:" + i;
    fragment.appendChild(li)
}

ul.appendChild(fragment)

2. innerHTML

createElement创建的元素可以使用innerHTML,createDocumentFragment创建的元素使用innerHTML并不能达到预期修改文档内容的效果,只是作为一个属性而已。两者的节点类型完全不同,createElement创建的是元素节点,节点类型为1,createDocumentFragment创建的元素在文档中没有对应的标记,因此在页面上只能在js中访问到。

<div id="outer"></div>
<input type="button" value="createElement" id="btn_1"/>
<input type="button" value="createDocumentFragment" id="btn_2"/>

<script type="text/javascript">
var fragment_1 = document.createDocumentFragment();
fragment_1.innerHTML = '<p>我是一个粉刷匠</p>';
document.body.appendChild(fragment_1);

var fragment_2 = document.createElement('p');
fragment_2.innerHTML = '粉刷本领强';
document.body.appendChild(fragment_2);
</script>

3. 重复操作

createElement创建的元素可以重复操作,添加之后就算从文档里面移除依旧归文档所有,可以继续操作,但是createDocumentFragment创建的元素是一次性的,添加之后无法再操作了(说明:这里的添加并不是添加了新创建的片段,因为上面说过,新创建的片段在文档内是没有对应的标签的,这里添加的片段是所有子节点)

<div id="outer"></div>
<input type="button" value="createElement" id="btn_1" />
<input type="button" value="createDocumentFragment" id="btn_2" />

<script  type="text/javascript">
function $(id) {
	return document.getElementById(id); 
}

var outer = $("outer");
var inner = $('inner'); 
$('btn_1').onclick = function(){
	var div = document.createElement('div');
	div.innerHTML = '<p>测试createElement</p>';
	document.body.appendChild(div);
	setTimeout(function(){
		outer.appendChild(div);
		setTimeout(function(){
			outer.removeChild(div);
		},1000)
	},1000)
}

$('btn_2').onclick = function(){
    var p = document.createElement('p');
    p.innerHTML = '测试DocumentFragment';
    var fragment = document.createDocumentFragment();
    fragment.appendChild(p);
    fragment.innerHTML = '<p>测试DocumentFragment</p>';
    fragment.innerHTML = '<span>测试学习DocumentFragment</span>';
    document.body.appendChild(fragment);
    setTimeout(function(){
    	outer.appendChild(fragment);//报错,因为此时文档内部已经能够不存在fragment了
		setTimeout(function(){
			outer.removeChild(fragment);
		},1000)
	},1000)
}
</script>