Detailed Explanation of the Usage of fragment. js in Vue

  • 2021-08-03 08:29:55
  • OfStack

Most of the content comes from jQuery. Of course, we also refer to component/domify. If you are interested in reading the original code here, you can find wrapMap in jQuery; As for domify, you can search directly to github, and there are few related items. Just look directly at index.js.

createDocumentFragment

What if you want to insert more than one element at a time on a single node, say 10000 nodes at a time?

The simplest and rudest way is:


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);
}

However, for well-known reasons, repeated operations on DOM will lead to page redrawing and backflow, which is very inefficient, and the page may be stuck, so this code is basically useless.

If DOM operation is carried out in segments, it can avoid blocking the page. js ninja cheats mentioned that setTimeout can be used for improvement:


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);

Of course, more conceivable ways should be to operate nodes directly in memory, interact with DOM tree after all nodes are gathered together, string all nodes on one div, and then hang div on DOM tree:


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);

As mentioned above, only interacting with DOM tree once will definitely improve the performance greatly, but an extra div is inserted. What if it is not interacting with nodes such as div, such as inserting th and td into table?

At this time, createDocumentFragment should go out, translated as "document fragment", according to the description of MDN:

DocumentFragments is a number of DOM nodes. They are not part 1 of the DOM tree. A common usage scenario is to create a document fragment, then insert the created DOM element into the document fragment, and finally insert the document fragment into the DOM tree. In the DOM tree, the document fragment is replaced with all its child elements.

Because the document fragment exists in memory and is not in the DOM tree, inserting child elements into the document fragment does not cause page backflow (calculation of element position and geometry). Therefore, using document fragments document fragments usually optimizes performance.

Simply put, it is the above example that does not need div transit version. When inserting, it directly replaces itself with its sub-elements, which is perfect.

Even IE6 supports this easy-to-use thing, although it is said that "anything that works well is not universal" (especially for a company browser).

The specific code looks like this:


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);

For specific performance tests, those who are interested can run all the codes once.

innerHTML

Convert a long string of 1 to the corresponding DOM node. Normally, innerHTML must come to mind first. The general process is to create an div node first, then div. innerHTML = str, take out children of div and put it in the place where it should be put, and throw away div itself.

What if you want to generate a single th node?

Try the above process:


var div = document.createElement('div');
div.innerHTML = '<th>xxx</th>';
console.log(div);

The actual output is (under chrome):


<div>xxx</div>

Didn't get what you wanted:


<div><th>xxx</th></div>

This result is understandable. After all, it is wrong to put an th into div. It is quite intelligent to directly remove the peripheral labels and throw the contents into div.

However, it can't be held up. Sometimes it is necessary to obtain an th node.

In fact, it's easy to do, just write it all:


var node = document.createElement('div');
node.innerHTML = '<table><tbody><tr><th>xxx</th></tr></tbody></table>';
//  It's what you want to peel off the outer layers of skin  th  It's over 
var depth = 3;
while(depth--) {
 node = node.lastChild;
 }
console.log(node.firstChild);

It can be seen that the result is exactly what you want.

fragment.js


//  That needs to be handled separately 1 Some special nodes 
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);
 //  Simple string case 
 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');
 //  Splice node string 
 node.innerHTML = prefix + templateString.trim() + suffix;
 //  Excluding the wrapping layer, leaving only the nodes for string conversion 
 while(depth--) node = node.lastChild;
 //  Only 1 The case of nodes 
 if(node.firstChild === node.lastChild) { 
  frag.appendChild(node.firstChild);
  return frag;
 }
 //  Multiple nodes, added in sequence to the  frag
 var child;
 while(child = node.firstChild) {
  frag.appendChild(child);
 }
 return frag;
}


Related articles: