jQuery.clean使用方法及思路分析_jquery
程序员文章站
2022-05-06 22:24:09
...
一、jQuery.clean使用方法
jQuery.clean( elems, context, fragment, scripts );
二、思路分析
1、处理参数context,确保其为文档根节点document
2、处理参数elems数组(循环遍历数组)
2.1、elem为数字,转换为字符串
2.2、elem为非法值,跳出本次循环
2.3、elem为字符串
2.4、字符串不存在实体编号或html标签,则创建文本节点
2.5、字符串为实体编号或html标签
创建一个div元素并插入到文档碎片中
处理xhtml风格标签
将elem包裹起来,并将包裹后的字符串作为div的innerHTML
如果包裹深度大于1,只留下第一层包裹元素
清除在ie6,7中空table标签自动加入的tbody
将在ie9以下浏览器中剔除的开头空白字符串作为div元素的第一个文本子节点
将elem重新赋值为div的子节点集合(nodeList对象),
移除本次循环中文档碎片中的div,保持下一次循环中干净的div元素
2.3、如果elem为文本节点,则直接添加到要返回的ret数组中,否则将elem(nodeList对象)中的节点合并到数组
2.4、修复在ie6、7中type为radio,checkbox类型的节点的选中状态(checked)失效的bug
3、处理参数fragment
3.1、将ret中各节点添加到文档碎片fragment中
3.2、提取节点中的script子节点,并将其添加到ret数组中,添加的script位置为其原父元素位置后面
4、返回ret数组
三、源码注释分析
1、函数中用到的变量及函数
var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
wrapMap = {
option: [ 1, "" ],
legend: [ 1, "" ],
thead: [ 1, "", "
" ],
tr: [ 2, "", "
" ],
td: [ 3, "
" ],
col: [ 2, "
" ],
area: [ 1, "" ],
_default: [ 0, "", "" ]
},
rxhtmlTag = /]*)\/>/gi,
rtagName = / rtbody = / rhtml = / rleadingWhitespace = /^\s+/,
rcheckableType = /^(?:checkbox|radio)$/,
rscriptType = /\/(java|ecma)script/i;
// 设置复选框checkbox或单选框radio表单元素的默认选中状态
function fixDefaultChecked( elem ) {
if ( rcheckableType.test( elem.type ) ) {
elem.defaultChecked = elem.checked;
}
}
// 创建一个安全的文档碎片
function createSafeFragment( document ) {
var list = nodeNames.split( "|" ),
safeFrag = document.createDocumentFragment(); // ie6,7,8浏览器把safeFrage作为HTMLDocument类型
// 针对ie9以下浏览器
if ( safeFrag.createElement ) {
while ( list.length ) {
safeFrag.createElement(
list.pop()
);
}
}
return safeFrag;
}
// 模拟ES5中Array的新功能
// 该函数API:http://www.css88.com/jqapi-1.8/#p=jQuery.grep
jQuery.extend({
grep: function( elems, callback, inv ) {
var retVal,
ret = [],
i = 0,
length = elems.length;
inv = !!inv;
// Go through the array, only saving the items
// that pass the validator function
for ( ; i retVal = !!callback( elems[ i ], i );
if ( inv !== retVal ) {
ret.push( elems[ i ] );
}
}
return ret;
}
});
2、源码分析
jQuery.extend({
clean: function( elems, context, fragment, scripts ) {
// 声明变量
var i, j, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags,
safe = context === document && safeFragment,
ret = [];
// 确保变量context为文档根节点document
if ( !context || typeof context.createDocumentFragment === "undefined" ) {
context = document;
}
// Use the already-created safe fragment if context permits
for ( i = 0; (elem = elems[i]) != null; i++ ) {
// 如果elem为数字,则将其转换为字符串
if ( typeof elem === "number" ) {
elem += "";
}
// 如果elem为undefined,跳出本次循环
if ( !elem ) {
continue;
}
// Convert html string into DOM nodes
// 转换数组项(字符串)为DOM节点
if ( typeof elem === "string" ) {
// 如果不存在html实体编号或标签,则创建文本节点
if ( !rhtml.test( elem ) ) {
elem = context.createTextNode( elem );
}
// 处理是html标签字符串的数组项
else {
// Ensure a safe container in which to render the html
// safe为#document-fragment类型,在ie9以下浏览器中,safe为HTMLDocument类型节点,且nodeNames数组为空
safe = safe || createSafeFragment( context );
// 创建一个div元素并将其插入到文档碎片中
div = context.createElement("div");
safe.appendChild( div );
// Fix "XHTML"-style tags in all browsers
// 除了area,br,col,embed,hr,img,input,link,meta,param这些标签外,
// 将开始标签末尾加入斜杠的标签转换为开始和结束标签
elem = elem.replace(rxhtmlTag, "$2>");
// Go to html and back, then peel off extra wrappers
// 获取左边第一个标签元素
tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase();
// 获取最外层元素的包裹元素,并将元素包裹在其中
wrap = wrapMap[ tag ] || wrapMap._default;
depth = wrap[0];
div.innerHTML = wrap[1] + elem + wrap[2];
// Move to the right depth
// 如果元素的包裹深度大于1,div重新赋值为元素最近的包裹元素(即:包含第一层包裹元素)
while ( depth-- ) {
div = div.lastChild;
}
// Remove IE's autoinserted from table fragments
// 在IE6,7中,清除字符串中空table标签中自动加入的tbody标签(手动加入的除外)
if ( !jQuery.support.tbody ) {
// String was a, *may* have spurious(伪造的)
" && !hasBody ?
jQuery.clean( elems, context, fragment, scripts );
二、思路分析
1、处理参数context,确保其为文档根节点document
2、处理参数elems数组(循环遍历数组)
2.1、elem为数字,转换为字符串
2.2、elem为非法值,跳出本次循环
2.3、elem为字符串
2.4、字符串不存在实体编号或html标签,则创建文本节点
2.5、字符串为实体编号或html标签
复制代码 代码如下:
创建一个div元素并插入到文档碎片中
处理xhtml风格标签
将elem包裹起来,并将包裹后的字符串作为div的innerHTML
如果包裹深度大于1,只留下第一层包裹元素
清除在ie6,7中空table标签自动加入的tbody
将在ie9以下浏览器中剔除的开头空白字符串作为div元素的第一个文本子节点
将elem重新赋值为div的子节点集合(nodeList对象),
移除本次循环中文档碎片中的div,保持下一次循环中干净的div元素
2.3、如果elem为文本节点,则直接添加到要返回的ret数组中,否则将elem(nodeList对象)中的节点合并到数组
2.4、修复在ie6、7中type为radio,checkbox类型的节点的选中状态(checked)失效的bug
3、处理参数fragment
3.1、将ret中各节点添加到文档碎片fragment中
3.2、提取节点中的script子节点,并将其添加到ret数组中,添加的script位置为其原父元素位置后面
4、返回ret数组
三、源码注释分析
1、函数中用到的变量及函数
复制代码 代码如下:
var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|" +
"header|hgroup|mark|meter|nav|output|progress|section|summary|time|video",
wrapMap = {
option: [ 1, "" ],
legend: [ 1, "" ],
thead: [ 1, "
tr: [ 2, "
td: [ 3, "
col: [ 2, "
area: [ 1, "" ],
_default: [ 0, "", "" ]
},
rxhtmlTag = /]*)\/>/gi,
rtagName = / rtbody = / rhtml = / rleadingWhitespace = /^\s+/,
rcheckableType = /^(?:checkbox|radio)$/,
rscriptType = /\/(java|ecma)script/i;
// 设置复选框checkbox或单选框radio表单元素的默认选中状态
function fixDefaultChecked( elem ) {
if ( rcheckableType.test( elem.type ) ) {
elem.defaultChecked = elem.checked;
}
}
// 创建一个安全的文档碎片
function createSafeFragment( document ) {
var list = nodeNames.split( "|" ),
safeFrag = document.createDocumentFragment(); // ie6,7,8浏览器把safeFrage作为HTMLDocument类型
// 针对ie9以下浏览器
if ( safeFrag.createElement ) {
while ( list.length ) {
safeFrag.createElement(
list.pop()
);
}
}
return safeFrag;
}
// 模拟ES5中Array的新功能
// 该函数API:http://www.css88.com/jqapi-1.8/#p=jQuery.grep
jQuery.extend({
grep: function( elems, callback, inv ) {
var retVal,
ret = [],
i = 0,
length = elems.length;
inv = !!inv;
// Go through the array, only saving the items
// that pass the validator function
for ( ; i retVal = !!callback( elems[ i ], i );
if ( inv !== retVal ) {
ret.push( elems[ i ] );
}
}
return ret;
}
});
2、源码分析
复制代码 代码如下:
jQuery.extend({
clean: function( elems, context, fragment, scripts ) {
// 声明变量
var i, j, elem, tag, wrap, depth, div, hasBody, tbody, len, handleScript, jsTags,
safe = context === document && safeFragment,
ret = [];
// 确保变量context为文档根节点document
if ( !context || typeof context.createDocumentFragment === "undefined" ) {
context = document;
}
// Use the already-created safe fragment if context permits
for ( i = 0; (elem = elems[i]) != null; i++ ) {
// 如果elem为数字,则将其转换为字符串
if ( typeof elem === "number" ) {
elem += "";
}
// 如果elem为undefined,跳出本次循环
if ( !elem ) {
continue;
}
// Convert html string into DOM nodes
// 转换数组项(字符串)为DOM节点
if ( typeof elem === "string" ) {
// 如果不存在html实体编号或标签,则创建文本节点
if ( !rhtml.test( elem ) ) {
elem = context.createTextNode( elem );
}
// 处理是html标签字符串的数组项
else {
// Ensure a safe container in which to render the html
// safe为#document-fragment类型,在ie9以下浏览器中,safe为HTMLDocument类型节点,且nodeNames数组为空
safe = safe || createSafeFragment( context );
// 创建一个div元素并将其插入到文档碎片中
div = context.createElement("div");
safe.appendChild( div );
// Fix "XHTML"-style tags in all browsers
// 除了area,br,col,embed,hr,img,input,link,meta,param这些标签外,
// 将开始标签末尾加入斜杠的标签转换为开始和结束标签
elem = elem.replace(rxhtmlTag, "$2>");
// Go to html and back, then peel off extra wrappers
// 获取左边第一个标签元素
tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase();
// 获取最外层元素的包裹元素,并将元素包裹在其中
wrap = wrapMap[ tag ] || wrapMap._default;
depth = wrap[0];
div.innerHTML = wrap[1] + elem + wrap[2];
// Move to the right depth
// 如果元素的包裹深度大于1,div重新赋值为元素最近的包裹元素(即:包含第一层包裹元素)
while ( depth-- ) {
div = div.lastChild;
}
// Remove IE's autoinserted from table fragments
// 在IE6,7中,清除字符串中空table标签中自动加入的tbody标签(手动加入的除外)
if ( !jQuery.support.tbody ) {
// String was a
网友评论
文明上网理性发言,请遵守 新闻评论服务协议
我要评论