Chapter 8 - DocumentFragment N

8.1 DocumentFragment object overview

The creation and use of a DocumentFragment node provides a light weight document DOM that is external to the live DOM tree. Think of a DocumentFragment as an empty document template that acts just like the live DOM tree, but only lives in memory, and its child nodes can easily be manipulated in memory and then appended to the live DOM.

8.2 Creating DocumentFragment"s using createDocumentFragment()

In the code below a DocumentFragment is created using createDocumentFragment() and <li>"s are appended to the fragment.

live code: http://jsfiddle.net/domenlightenment/6e3uX

<!DOCTYPE html>
<html lang="en">
<body>

<script>
var docFrag = document.createDocumentFragment();["blue", "green", "red", "blue", "pink"].forEach(function(e) {    var li = document.createElement("li");    li.textContent = e;    docFrag.appendChild(li);});console.log(docFrag.textContent); //logs bluegreenredbluepink

</script>
</body>
</html>

Using a documentFragment to create node structures in memory is extrememly efficent when it comes time to inject the documentFragment into live node structures.

You might wonder what is the advantage to using a documentFragment over simply creating (viacreateElement()) a <div> in memory and working within this <div> to create a DOM structure. The follow are the differences.

  • A document fragment may contain any kind of node (except <body> or <html>) where as an element may not
  • The document fragment itself, is not added to the DOM when you append a fragment. The contents of the node are. As opposed to appending an element node in which the element itself is part of the appending.
  • When a document fragment is appended to the DOM it transfers from the document fragment to the place its appended. Its no longer in memory in the place you created it. This is not true for element nodes that are temperately used to contained nodes briefly and then are moved to the live DOM.

8.3 Adding a DocumentFragment to the live DOM

By passing the appendChild() and insertBefore() node methods a documentFragment argument the child nodes of the documentFragment are transported as children nodes to the DOM node the methods are called on. Below we create a documentfragment, add some <li>"s to it, then append these new element nodes to the live DOM tree using appendChild().

live code: http://jsfiddle.net/domenlightenment/Z2LpU

<!DOCTYPE html>
<html lang="en">
<body>

<ul></ul>

<script>

var ulElm = document.queryselector("ul");var docFrag = document.createDocumentFragment();["blue", "green", "red", "blue", "pink"].forEach(function(e) {    var li = document.createElement("li");    li.textContent = e;    docFrag.appendChild(li);});
ulElm.appendChild(docFrag);

//logs <ul><li>blue</li><li>green</li><li>red</li><li>blue</li><li>pink</li></ul>console.log(document.body.innerHTML);

</script>
</body>
</html>

Notes

Document fragments passed as arguments to inserting node methods will insert the entire child node structure ignoring the documentFragment node itself.

8.4 Using innerHTML on a documentFragment

Creating a DOM structure in memory using node methods can be verbose and laboring. One way around this would be to created a documentFragment, append a <div> to this fragment because innerHTML does not work on document fragments, and then use the innerHTML property to update the fragment with a string of HTML. By doing this a DOM structure is crafted from the HTML string. In the code below I construct a DOM structure that I can then treat as a tree of nodes and not just a JavaScript string.

live code: http://jsfiddle.net/domenlightenment/4W9sH

<!DOCTYPE html>
<html lang="en">
<body>

<script>

//create a <div> and document fragment
var divElm = document.createElement("div");var docFrag = document.createDocumentFragment();
//append div to document fragmentdocFrag.appendChild(divElm);

//create a DOM structure from a string
docFrag.querySelector("div").innerHTML = "<ul><li>foo</li><li>bar</li></ul>";
//the string becomes a DOM structure I can call methods on like querySelectorAll()
//Just don"t forget the DOM structure is wrapped in a <div>
console.log(docFrag.querySelectorAll("li").length); //logs 2

</script>
</body>
</html>

When it comes time to append a DOM structure created using a documentFragment and <div> you"ll want to append the structure skipping the injection of the <div>.

live code: http://jsfiddle.net/domenlightenment/kkyKJ

<!DOCTYPE html>
<html lang="en">
<body>

<div></div>

<script>

//create a <div> and document fragment
var divElm = document.createElement("div");var docFrag = document.createDocumentFragment();
//append div to document fragmentdocFrag.appendChild(divElm);

//create a DOM structure from a string
docFrag.querySelector("div").innerHTML = "<ul><li>foo</li><li>bar</li></ul>";
//append, starting with the first child node contained inside of the <div>
document.querySelector("div").appendChild(docFrag.querySelector("div").firstChild);

//logs <ul><li>foo</li><li>bar</li></ul>
console.log(document.querySelector("div").innerHTML);

</script>
</body>
</html>

Notes

In addtion to DocumentFragment we also have DOMParser to look forward too. DOMParser can parse HTML stored in a string into a DOM Document. It"s only supported in Opera & Firefox as of today, but a polyfill is avaliable. Of course, if you need a stand alone HTML to DOM script try domify.

8.5 Leaving a fragments containing nodes in memory by cloning

When appending a documentFragment the nodes contained in the Fragment are moved from the Fragment to the structure you are appending too. To leave the contents of a fragment in memory, so the nodes remain after appending, simply clone using cloneNode() the documentFragment when appending. In the code below instead of tranporting the <li>"s from the document fragment I clone the 
<li>"s, which keeps the <li>"s being clonded in memory inside of the documentFragment node.

live code: http://jsfiddle.net/domenlightenment/bcJGS

<!DOCTYPE html>
<html lang="en">
<body>

<ul></ul>

<script>

//create ul element and document fragment
var ulElm = document.querySelector("ul");var docFrag = document.createDocumentFragment();
//append li"s to document fragment["blue", "green", "red", "blue", "pink"].forEach(function(e) {    var li = document.createElement("li");    li.textContent = e;    docFrag.appendChild(li);});
//append cloned document fragment to ul in live DOM
ulElm.appendChild(docFrag.cloneNode(true));

//logs <li>blue</li><li>green</li><li>red</li><li>blue</li><li>pink</li>console.log(document.querySelector("ul").innerHTML);

//logs [li,li,li,li,li] 
console.log(docFrag.childNodes);

</script>
</body>
</html>
文章导航