zoukankan      html  css  js  c++  java
  • jQuery 3.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

    buildFragment 在 jQuery 各个版本中的演变

    1. 1.0.x ~ 1.3.x 中没有 buildFragment 函数,即没有抽取出该函数为 domManip 服务
    2. 1.4.x 中首次引入 buildFragment ,当时是挂在 jQuery 上的静态方法,有三个参数 args, nodes, scripts。一直到2.x.x 依然是公开可以访问的
    3. 3.x.x 开始 buildFragment 变成了一个私有函数,只能在 jQuery 代码内部访问,客户端程序员无法访问
  • 相关阅读:
    GhostBSD 3.0RC3,基于GNOME的FreeBSD
    Nagios 3.4.3 发布,企业级监控系统
    Jolokia 1.0.6 发布, JMX远程访问方法
    微软希望开发人员不要使 WebKit 成为新版 IE6
    Kwort Linux 3.5 正式版发布
    EJDB 1.0.24 发布,嵌入式 JSON 数据库引擎
    Pale Moon 15.3 Firefox“苍月”优化版发布
    Galera Load Balancer 0.8.1 发布
    SmartSVN V7.5 正式发布
    PostgresQL建立索引如何避免写数据锁定
  • 原文地址:https://www.cnblogs.com/snandy/p/5760742.html
Copyright © 2011-2022 走看看