jQuery.parseHTML详解

parseHTML是jQuery内部解析html字符串的方法


jQuery.parseHTML = function( data, context, keepScripts ) {
        // data必须是字符串,否则返回空数组
	if ( typeof data !== "string" ) {
		return [];
	}
        // 如果context是布尔值,则用来指示
	if ( typeof context === "boolean" ) {
		keepScripts = context;
		context = false;
	}

	var base, parsed, scripts;
         // 如果context为空
	if ( !context ) {

		// 如果支持crheateHTMLDocument ,则创建一个,并设置base为当前document的href
		if ( support.createHTMLDocument ) {
			context = document.implementation.createHTMLDocument( "" );
			base = context.createElement( "base" );
			base.href = document.location.href;
			context.head.appendChild( base );
		} else {
                  // 否则直接使用document
			context = document;
		}
	}
        // 匹配是否为html标签字符串(不能包含属性),更多信息可以查看点击查看rsignleTag专讲
	parsed = rsingleTag.exec( data );
	scripts = !keepScripts && [];

	// 如果匹配到标签名称,使用context的createElement方法创建标签
	if ( parsed ) {
		return [ context.createElement( parsed[ 1 ] ) ];
	}
        // 调用buildFragment进行处理,真正的处理代码就在这个里面
	parsed = buildFragment( [ data ], context, scripts );
        // 如果存在script,将script移除。
	if ( scripts && scripts.length ) {
		jQuery( scripts ).remove();
	}

	return jQuery.merge( [], parsed.childNodes );
};

再来看一看buildFragment。


define( [
	"../core",
	"./var/rtagName",
	"./var/rscriptType",
	"./wrapMap",
	"./getAll",
	"./setGlobalEval"
], function( jQuery, rtagName, rscriptType, wrapMap, getAll, setGlobalEval ) {

"use strict";
// 匹配<或者 &#?\w+;
var rhtml = /<|&#?\w+;/;

function buildFragment( elems, context, scripts, selection, ignored ) {
	var elem, tmp, tag, wrap, contains, j,
 /**
  * 使用createDocumentFragment可以获得更多性能优化,详情参见createDocumentFragement方法
  */
		fragment = context.createDocumentFragment(),
		nodes = [],
		i = 0,
		l = elems.length;

	for ( ; i < l; i++ ) {
		elem = elems[ i ];

		if ( elem || elem === 0 ) {

			// 直接添加节点
			if ( jQuery.type( elem ) === "object" ) {
				jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );

			// 将非html代码转化成textNode
			} else if ( !rhtml.test( elem ) ) {
				nodes.push( context.createTextNode( elem ) );

			// 将html转成DOM
			} else {
                               // 创建一个div,将html代码注入,即可得到相应的dom信息
				tmp = tmp || fragment.appendChild( context.createElement( "div" ) );

				// 获得elem的标签名称
				tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
                                //tag如果是option,thead,col,tr,td就包裹前置、后缀元素,否则两者为空
				wrap = wrapMap[ tag ] || wrapMap._default;
//将形如<div align="center" />这样的html代码转化成<div align="center"></div>
				tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];

				// 计数器初始位置,如果有不同的前置则起始值也会变化,令tmp等于包裹在中间的元素
				j = wrap[ 0 ];
				while ( j-- ) {
					tmp = tmp.lastChild;
				}
                                // 将tmp的所有子节点合并到nodes中
				jQuery.merge( nodes, tmp.childNodes );
				tmp = fragment.firstChild;
				tmp.textContent = "";
			}
		}
	}

	fragment.textContent = "";

        // 循环处理每一个node
	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;
		}
                // 查找elem是否已经存在于对应的document中
		contains = jQuery.contains( elem.ownerDocument, elem );

		// 将elem添加到fragment中,如果加入的child中包含script,则将之取出,做特殊处理
		tmp = getAll( fragment.appendChild( elem ), "script" );

		// 如果elem已经添加到文档中了,只要执行script即可,通过setGlobalEval来实现
		if ( contains ) {
			setGlobalEval( tmp );
		}

		// 如果keepScripts为true,scripts为[]
		if ( scripts ) {
			j = 0;
			while ( ( elem = tmp[ j++ ] ) ) {
				if ( rscriptType.test( elem.type || "" ) ) {
					scripts.push( elem );
				}
			}
		}
	}

	return fragment;
}

return buildFragment;
} );
Show Comments

Get the latest posts delivered right to your inbox.