你的位置:首页 > Java教程

[Java教程]jQuery3.0的buildFragment


在 jQuery3.0中,buildFragment 是一个私有函数,用来构建一个包含子节点 fragment 对象。这个 fragment 在 DOM1 中就已经有了,所有浏览器都支持。当频繁操作(添加、插入) DOM 时使用该方法可以提高性能,John resig 做过一个测试及一篇博客。

 

jQuery3.0 中 buildFragment 只在 domManip 和 jQuery.parseHTML 中使用,domManip 则被 DOM 操作如 append、prepend、before、after 等方法的所依赖。如下图

 

buildFragment 函数有 5 个参数,源码如下

function buildFragment( elems, context, scripts, selection, ignored ) {	var elem, tmp, tag, wrap, contains, j,		fragment = context.createDocumentFragment(),		nodes = [],		i = 0,		l = elems.length;	for ( ; i < l; i++ ) {		elem = elems[ i ];		if ( elem || elem === 0 ) {			// Add nodes directly			if ( jQuery.type( elem ) === "object" ) {				// Support: Android <=4.0 only, PhantomJS 1 only				// push.apply(_, arraylike) throws on ancient WebKit				jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );			// Convert non-html into a text node			} else if ( !rhtml.test( elem ) ) {				nodes.push( context.createTextNode( elem ) );			// Convert html into DOM nodes			} else {				tmp = tmp || fragment.appendChild( context.createElement( "div" ) );				// Deserialize a standard representation				tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();				wrap = wrapMap[ tag ] || wrapMap._default;				tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];				// Descend through wrappers to the right content				j = wrap[ 0 ];				while ( j-- ) {					tmp = tmp.lastChild;				}				// Support: Android <=4.0 only, PhantomJS 1 only				// push.apply(_, arraylike) throws on ancient WebKit				jQuery.merge( nodes, tmp.childNodes );				// Remember the top-level container				tmp = fragment.firstChild;				// Ensure the created nodes are orphaned (#12392)				tmp.textContent = "";			}		}	}	// Remove wrapper from fragment	fragment.textContent = "";	i = 0;	while ( ( elem = nodes[ i++ ] ) ) {		// Skip elements already in the context collection (trac-4087)		if ( selection && jQuery.inArray( elem, selection ) > -1 ) {			if ( ignored ) {				ignored.push( elem );			}			continue;		}		contains = jQuery.contains( elem.ownerDocument, elem );		// Append to fragment		tmp = getAll( fragment.appendChild( elem ), "script" );		// Preserve script evaluation history		if ( contains ) {			setGlobalEval( tmp );		}		// Capture executables		if ( scripts ) {			j = 0;			while ( ( elem = tmp[ j++ ] ) ) {				if ( rscriptType.test( elem.type || "" ) ) {					scripts.push( elem );				}			}		}	}	return fragment;}

 

该方法主要执行步骤

  1. 通过第二个参数 content 创建 fragment
  2. 通过第一个参数 elems 构建 nodes ,将 elems 内元素转成 DOM 元素存放于数组 nodes 中
  3. 将 nodes 里元素循环放入添加到文档碎片 fragment 上
  4. 返回 fragment

 

重点在第 2 步,构建 nodes,有 3 种情形

  1. elem 是 DOM 元素(根据nodeType判断),直接放入 nodes 数组中
  2. elem 是字符串且不是 HTML tag,创建文本节点对象(textNode),放入 nodes 数组中
  3. elem 是字符串且是 HTML tag,将其转成 DOM 元素,放入 nodes 数组中

 

如图示

 

后面的两个参数需要注意下

1. 最后两个参数 selection 和 ignored 只在 replaceWith 方法里使用。需要了解的是 replaceWith 只做节点替换,不会替换先前元素的所有数据(Data),比如绑定事件,$.data 都不会被新元素拥有。

 

2. scripts 参数只在 jQuery.parseHTML 方法里使用(domManip里传false),当 jQuery.parseHTML 的第三个参数 keepScripts 为 false 时将删除节点里所有的 script tag