jQuery源码分析研究学习笔记-jQuery.clean()(七)
jQuery.clean( elems, context, fragment, scripts )
参数elems:数组,包含了待转换的HTML是代码 参数context:文档对象,该参数在方法jQuery.buildFragment()中被修正为正确的文档对象,稍后会调用它的方法createTextNode()创建文本节点、调用方法createElement()创建临时div元素。 参数fragment:文档片段,作为存放转换后的DOM元素的占位符,该参数在jQuery.buildFragment()中被创建 参数scripts:数组,用于存放转换后的DOM元素中的script元素
clean: function( elems, context, fragment, scripts ) { var checkScriptType, script, j, ret = []; //修正文档对象context context = context || document; // 若文档对象context没有createElement方法,就尝试读取context.ownerDocument或context[0].ownwerDocument,如果都没,默认为文档对象document if ( typeof context.createElement === "undefined" ) { context = context.ownerDocument || context[0] && context[0].ownerDocument || document; } //遍历待转换的HTML代码数组 //for循环语句完成了循环变量elem定义、赋值和判断有效性,减少了代码量 //判断elem有效性时候使用的"!=",可以同时过滤null和undefined,却不会过滤整型数字0 for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { if ( typeof elem === "number" ) { elem += ""; //如果elem是数字,让elem自加一个空字符串,把elem转换为字符串 } //如果!elem为true,那么跳过本次循环,执行下次循环,主要用于过滤空字符串的情况, if ( !elem ) { continue; } // 若elem是字符串,即html代码,执行转换html代码为DOM元素 if ( typeof elem === "string" ) { // rhtml = /<|?\w+;/ if ( !rhtml.test( elem ) ) { //若html代码中不包含标签、字符串和数字代码,则调用原生方法document.createTextNode()创建文本节点 elem = context.createTextNode( elem ); } else { // rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig //修正自关闭标签 elem = elem.replace(rxhtmlTag, "<$1>$2>"); // 提取html代码中的标签部分,删除了前导空白符和左尖括号,并转换为小写赋值给变量wrap var tag = ( rtagName.exec( elem ) || ["", ""] )[1].toLowerCase(), wrap = wrapMap[ tag ] || wrapMap._default, depth = wrap[0], div = context.createElement("div"), safeChildNodes = safeFragment.childNodes, remove; // 文档对像context是当前文档对象,把临时div元素插入已创建的安全文档片段safeFragment中, if ( context === document ) { safeFragment.appendChild( div ); } else { // 调用函数createSafeFragment()在文档对象context上创建一个新的安全文档片段,然后插入临时div元素 createSafeFragment( context ).appendChild( div ); } //为html代码包裹必要的父元素,然后赋值给临时div元素的innerHTML属性,浏览器自动生成dom元素 div.innerHTML = wrap[1] + elem + wrap[2]; // 循环层层剥去必要的父标签,然后赋值给临时div元素,最终变量div将指向HTML代码对于那个的DOM元素的父元素 while ( depth-- ) { div = div.lastChild; } // 移除IE6/7自动插入的空tbody元素 if ( !jQuery.support.tbody ) { // rtbody = /
,但是html代码中没有tbody标签,即html代码中含有thead、tfoot、colgroup、caption之一或多个,浏览器生成dom元素时可能自动插入空tbody元素,此时变量div指向table wrap[1] === "" && !hasBody ? div.childNodes : []; //遍历tbody,移除空的tbody元素 //判断是否是tbody元素,若是删除此元素 if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length ) { tbody[ j ].parentNode.removeChild( tbody[ j ] ); } } } // 插入IE6/7/8自动剔除的前导空白符 // rleadingWhitespace = /^\s+/ if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) { div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild ); } elem = div.childNodes; // Clear elements from DocumentFragment (safeFragment or otherwise) // to avoid hoarding elements. Fixes #11356 if ( div ) { div.parentNode.removeChild( div ); // Guard against -1 index exceptions in FF3.6 if ( safeChildNodes.length > 0 ) { remove = safeChildNodes[ safeChildNodes.length - 1 ]; if ( remove && remove.parentNode ) { remove.parentNode.removeChild( remove ); } } } } } // 在ie6/7中,复选框和单选框按钮插入DOM树后,其选中状态checked会丢失, var len; //通过在插入前把属性checked的值赋值给属性defaultChecked,来解决这个问题 if ( !jQuery.support.appendChecked ) { if ( elem[0] && typeof (len = elem.length) === "number" ) { for ( j = 0; j < len; j++ ) { //遍历转换后的DOM元素集合,在每个元素上调用函数findInputs(elem) findInputs( elem[j] ); } } else { findInputs( elem ); } } if ( elem.nodeType ) { ret.push( elem ); } else { ret = jQuery.merge( ret, elem ); } } //如果传入了fragment,则遍历数组ret,提取所有合肥的script元素存在数组script,并把其他元素插入文档片段fragment if ( fragment ) { checkScriptType = function( elem ) { return !elem.type || rscriptType.test( elem.type ); }; for ( i = 0; ret[i]; i++ ) { script = ret[i]; if ( scripts && jQuery.nodeName( script, "script" ) && (!script.type || rscriptType.test( script.type )) ) { scripts.push( script.parentNode ? script.parentNode.removeChild( script ) : script ); } else { if ( script.nodeType === 1 ) { var jsTags = jQuery.grep( script.getElementsByTagName( "script" ), checkScriptType ); ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) ); } fragment.appendChild( script ); } } } return ret; }函数findInputs()和fixDefaultChecked()
// 通过函数findInputs(elem)找出其中的复选框和单选按钮,然后调用fixDefaultChecked(elem)把属性checked的值赋值给属性defaultCheckedfunction fixDefaultChecked( elem ) { if ( elem.type === "checkbox" || elem.type === "radio" ) { elem.defaultChecked = elem.checked; }}// Finds all inputs and passes them to fixDefaultCheckedfunction findInputs( elem ) { var nodeName = ( elem.nodeName || "" ).toLowerCase(); if ( nodeName === "input" ) { fixDefaultChecked( elem ); // Skip scripts, get other children } else if ( nodeName !== "script" && typeof elem.getElementsByTagName !== "undefined" ) { jQuery.grep( elem.getElementsByTagName("input"), fixDefaultChecked ); }}
jQuery.clean( elems, context, fragment, scripts )执行步骤:
创建一个临时div元素,并插入一个安全文档片段中。为HTML代码包裹必要的父标签,然后赋值给临时div元素的innerHTML属性,从而将HTML代码转换为DOM元素之后再层层剥去包裹的父元素,得到转换后的DOM元素移除IE6/7自动插入的空tbody元素,插入IE6/7/8自动过滤的前导空白符取到转换后的DOM元素集合在IE6/7中修正复选框和单选按钮的选中状态合并转换后的DOM元素如果传入了文档片段fragment,则提取所有合法的script元素存入数组scripts,并把其他元素插入文档片段fragment最后返回转换后的DOM元素数组
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
暂时没有评论,来抢沙发吧~