jQuery1.3代码深度分析(clean)

// 把html转换成Dom元素,elems多个html string 的数组1.2.6得时候只有两个参数,新的版本中加了fragment第三个参数
clean: function( elems, context, fragment ) {
        context = context || document;
        //默认的上下文是document
        //在IE中!context.createElement行不通,因为它返回对象类型
        // !context.createElement fails in IE with an error but returns typeof 'object'
        if ( typeof context.createElement === "undefined" )
            //这里支持context为jQuery对象,取第一个元素。
            context = context.ownerDocument || context[0] && context[0].ownerDocument || document;

        // If a single string is passed in and it's a single tag
        // just do a createElement and skip the rest
        //这是1.3新加的,如果是单独得标签比如:$('<div />') 直接调用createElement
        if ( !fragment && elems.length === 1 && typeof elems[0] === "string" ) {
            var match = /^<(\w+)\s*\/?>$/.exec(elems[0]);
            if ( match )
                return [ context.createElement( match[1] ) ];
        }

        var ret = [], scripts = [], div = context.createElement("div");

        jQuery.each(elems, function(i, elem){
            if ( typeof elem === "number" )
                elem += '';
            // 把int 转换成string的最高效的方法
            if ( !elem )
                return;

            // Convert html string into DOM nodes // 转换html为Dom元素
            if ( typeof elem === "string" ) {
                // Fix "XHTML"-style tags in all browsers
                // 修正 "XHTML"-style 标签,对于如<div/>的形式修改为<div></div>
                //但是对于(abbr|br|col|img|input|link|meta|param|hr|area|embed)不修改   
                //front=(<(\w+)[^>]*?)
                elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){
                    return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ?
                        all :
                        front + "></" + tag + ">";
                });

                // Trim whitespace, otherwise indexOf won't work as expected
                // 去空格,否则indexof不能正常工作
                var tags = jQuery.trim( elem ).toLowerCase();
               // 有些标签必须是有一些约束的,比如<option>必须在<select></select>中间
               // 下面的代码在大部分是对<table>中子元素进行修正。数组中第一个元素为深度                           
               //&&>||
                var wrap =
                    // option or optgroup
                    !tags.indexOf("<opt") &&
                    [ 1, "<select multiple='multiple'>", "</select>" ] ||

                    !tags.indexOf("<leg") &&
                    [ 1, "<fieldset>", "</fieldset>" ] ||

                    tags.match(/^<(thead|tbody|tfoot|colg|cap)/) &&
                    [ 1, "<table>", "</table>" ] ||

                    !tags.indexOf("<tr") &&
                    [ 2, "<table><tbody>", "</tbody></table>" ] ||

                     // <thead> matched above
                    (!tags.indexOf("<td") || !tags.indexOf("<th")) &&
                    [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ] ||

                    !tags.indexOf("<col") &&
                    [ 2, "<table><tbody></tbody><colgroup>", "</colgroup></table>" ] ||

                    // IE can't serialize <link> and <script> tags normally
                    !jQuery.support.htmlSerialize &&
                    [ 1, "div<div>", "</div>" ] ||

                    [ 0, "", "" ];

                // Go to html and back, then peel off extra wrappers
                // 包裹html之后,采用innerHTML转换成Dom
                div.innerHTML = wrap[1] + elem + wrap[2];

                // Move to the right depth
                while ( wrap[0]-- )
                    div = div.lastChild;

                // Remove IE's autoinserted <tbody> from table fragments
                if ( !jQuery.support.tbody ) {

                    // String was a <table>, *may* have spurious <tbody>
                    var tbody = !tags.indexOf("<table") && tags.indexOf("<tbody") < 0 ?
                        div.firstChild && div.firstChild.childNodes :

                        // String was a bare <thead> or <tfoot>
                        wrap[1] == "<table>" && tags.indexOf("<tbody") < 0 ?
                            div.childNodes :
                            [];

                    for ( var j = tbody.length - 1; j >= 0 ; --j )
                        if ( jQuery.nodeName( tbody[ j ], "tbody" ) && !tbody[ j ].childNodes.length )
                            tbody[ j ].parentNode.removeChild( tbody[ j ] );

                    }

                // IE completely kills leading whitespace when innerHTML is used
                if ( !jQuery.support.leadingWhitespace && /^\s/.test( elem ) )
                    div.insertBefore( context.createTextNode( elem.match(/^\s*/)[0] ), div.firstChild );
                
                elem = jQuery.makeArray( div.childNodes );
            }

            if ( elem.nodeType )
                ret.push( elem );
            else
                ret = jQuery.merge( ret, elem );

        });
       //这段是新加的处理js代码,同时也取消了form的处理
        if ( fragment ) {
            for ( var i = 0; ret[i]; i++ ) {
                if ( jQuery.nodeName( ret[i], "script" ) && (!ret[i].type || ret[i].type.toLowerCase() === "text/javascript") ) {
                    scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );
                } else {
                    if ( ret[i].nodeType === 1 )
                        ret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName("script"))) );
                    fragment.appendChild( ret[i] );
                }
            }
            
            return scripts;
        }

        return ret;
    },  

        },
这 个方法主要解决html到dom的转换,在1.3选择器中接着比较重要就是xpath的选择了。以前得版本是自己写的,新得版本是整合了Sizzle,类 似jQuery.find=Sizzle.find,这样代码重载jQuery得选择器,下节再讲Sizzle,实际上选择得原理和1.2.6是一样的, 只是有点细节上的区别。
posted @ 2009-11-02 20:40  麦飞  阅读(540)  评论(0编辑  收藏  举报