jQuery源码分析研究学习笔记-jQuery.clean()(七)

来源:互联网 发布:js购物车结算页面 编辑:程序博客网 时间:2024/06/06 01:47

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 = /<tbody/i                        //检测html代码中是否含有tbody标签                        var hasBody = rtbody.test(elem),                        //表示HTML代码中含有table标签,没有tbody标签,浏览器生成dom元素时可能自动插入空tbody元素。                            tbody = tag === "table" && !hasBody ?                                div.firstChild && div.firstChild.childNodes :                                // 表示为HTML代码包裹了父标签<table>,但是html代码中没有tbody标签,即html代码中含有thead、tfoot、colgroup、caption之一或多个,浏览器生成dom元素时可能自动插入空tbody元素,此时变量div指向table                                wrap[1] === "<table>" && !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 )执行步骤:

  1. 创建一个临时div元素,并插入一个安全文档片段中。
  2. 为HTML代码包裹必要的父标签,然后赋值给临时div元素的innerHTML属性,从而将HTML代码转换为DOM元素之后再层层剥去包裹的父元素,得到转换后的DOM元素
  3. 移除IE6/7自动插入的空tbody元素,插入IE6/7/8自动过滤的前导空白符
  4. 取到转换后的DOM元素集合
  5. 在IE6/7中修正复选框和单选按钮的选中状态
  6. 合并转换后的DOM元素
  7. 如果传入了文档片段fragment,则提取所有合法的script元素存入数组scripts,并把其他元素插入文档片段fragment
  8. 最后返回转换后的DOM元素数组
0 0
原创粉丝点击