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