zoukankan      html  css  js  c++  java
  • jquery 源码分析八

    在各种聚会,毕设任务后。。。我又回来了!!!

    继续分析jquery中的sizzle源码

    在Sizzle主函数以后,先是一些列的零散函数,为后面support检测,事件代理提供先期方法。这些函数内容比较简单,就直接分析掉了:

    // 为function作标记
    function markFunction( fn ) {
        fn[ expando ] = true;
        return fn;
    }
    
    /**
     * 用一个div元素来做一些检测
     */
    function assert( fn ) {
        var div = document.createElement("div");
    
        try {
            return !!fn( div );
        } catch (e) {
            return false;
        } finally {
            // 将div移除
            if ( div.parentNode ) {
                div.parentNode.removeChild( div );
            }
            // 释放缓存
            div = null;
        }
    }
    // 给所有的attrs添加相同的handler
    function addHandle( attrs, handler ) {
        var arr = attrs.split("|"),
            i = attrs.length;
    
        while ( i-- ) {
            Expr.attrHandle[ arr[i] ] = handler;
        }
    }
    /**
     * 检测两个元素的顺序
     * 返回小于0 则a在b前, 大于 0 则a在b后
     */
    function siblingCheck( a, b ) {
        var cur = b && a,
            diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
                ( ~b.sourceIndex || MAX_NEGATIVE ) -
                ( ~a.sourceIndex || MAX_NEGATIVE );
    
        // 如果可以的话,就用IE的sourceIndex
        if ( diff ) {
            return diff;
        }
    
        // 检测b是否在a后面
        if ( cur ) {
            while ( (cur = cur.nextSibling) ) {
                if ( cur === b ) {
                    return -1;
                }
            }
        }
    
        return a ? 1 : -1;
    }
    /**
     *会返回一个函数,用于检测input的type
     */
    function createInputPseudo( type ) {
        return function( elem ) {
            var name = elem.nodeName.toLowerCase();
            return name === "input" && elem.type === type;
        };
    }
    
    /**
     * 返回一个函数,用于检测input或buttong的type
     */
    function createButtonPseudo( type ) {
        return function( elem ) {
            var name = elem.nodeName.toLowerCase();
            return (name === "input" || name === "button") && elem.type === type;
        };
    }
    
    /**
     * 返回一个函数,用于检测元素的位置
     */
    function createPositionalPseudo( fn ) {
        return markFunction(function( argument ) {
            argument = +argument;
            return markFunction(function( seed, matches ) {
                var j,
                    matchIndexes = fn( [], seed.length, argument ),
                    i = matchIndexes.length;
    
                // 找到特定位置的元素
                while ( i-- ) {
                    if ( seed[ (j = matchIndexes[i]) ] ) {
                        seed[j] = !(matches[j] = seed[j]);
                    }
                }
            });
        });
    }

    接下来就是setDocument了,它根据现有的document来设置,并在函数体中做了很多关于support的检测,它会返回当前的document

    看了很久发现要写好多好多东西,这个函数居然有400行,容我慢慢注释下,后面会补上

     =========================================分割线========================================

    好,下面上源码,和以前一样,里面调用的函数在下面会讲到,其中rbuggyMatches是支撑matches的正则串,rbuggyQSA是支撑qsa的正则串

    setDocument = Sizzle.setDocument = function( node ) {
        var hasCompare,
            // 如果没有node,就直接去preferredDoc
            doc = node ? node.ownerDocument || node : preferredDoc,
            parent = doc.defaultView;
    
        // 如果没有document或者documentElement不可访问,就直接返回
        if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
            return document;
        }
    
        // 设置document
        document = doc;
        docElem = doc.documentElement;
    
        // 开始关于support的检测
        documentIsHTML = !isXML( doc );
    
        // Support: IE>8
        // 在iframe中,如果需要访问到document,在iframe重载之后
        // 当要访问document时,IE会报出"permission denied"错误
        // IE6-8 d不支持defaultView,所以parent会未定义
        if ( parent && parent !== parent.top ) {
            // IE11 不支持attachEvent。。。。
            if ( parent.addEventListener ) {
                parent.addEventListener( "unload", function() {
                    setDocument();
                }, false );
            } else if ( parent.attachEvent ) {
                parent.attachEvent( "onunload", function() {
                    setDocument();
                });
            }
        }
    
        /* 各种属性
        ---------------------------------------------------------------------- */
    
        // Support: IE<8
        // 检测getAttribute是否真的返回相应的attribute而不是属性
        support.attributes = assert(function( div ) {
            div.className = "i";
            return !div.getAttribute("className");
        });
    
        /* getElement(s)By*
        ---------------------------------------------------------------------- */
    
        // 检测 getElementsByTagName("*") 是否只返回元素
        support.getElementsByTagName = assert(function( div ) {
            div.appendChild( doc.createComment("") );
            return !div.getElementsByTagName("*").length;
        });
    
        // 检测是否getElementsByClassName是否工作正常
        support.getElementsByClassName = rnative.test( doc.getElementsByClassName ) && assert(function( div ) {
            div.innerHTML = "<div class='a'></div><div class='a i'></div>";
    
            div.firstChild.className = "i";
            // Support: Opera<10
            // 判断是否可以得到非开头的class
            return div.getElementsByClassName("i").length === 2;
        });
    
        // Support: IE<10
        // 检测getElementById 返回的是不是 elements by name
        support.getById = assert(function( div ) {
            docElem.appendChild( div ).id = expando;
            return !doc.getElementsByName || !doc.getElementsByName( expando ).length;
        });
    
        // ID find and filter
        if ( support.getById ) {
            Expr.find["ID"] = function( id, context ) {
                if ( typeof context.getElementById !== strundefined && documentIsHTML ) {
                    var m = context.getElementById( id );
                    // 检测是否返回了已经删除了的元素
                    return m && m.parentNode ? [m] : [];
                }
            };
            Expr.filter["ID"] = function( id ) {
                var attrId = id.replace( runescape, funescape );
                return function( elem ) {
                    return elem.getAttribute("id") === attrId;
                };
            };
        } else {
            // Support: IE6/7
            // getElementById并不可靠
            delete Expr.find["ID"];
    
            Expr.filter["ID"] =  function( id ) {
                var attrId = id.replace( runescape, funescape );
                return function( elem ) {
                    var node = typeof elem.getAttributeNode !== strundefined && elem.getAttributeNode("id");
                    return node && node.value === attrId;
                };
            };
        }
    
        // Tag
        Expr.find["TAG"] = support.getElementsByTagName ?
            function( tag, context ) {
                if ( typeof context.getElementsByTagName !== strundefined ) {
                    return context.getElementsByTagName( tag );
                }
            } :
            function( tag, context ) {
                var elem,
                    tmp = [],
                    i = 0,
                    results = context.getElementsByTagName( tag );
    
                // 将不是element的元素剔除
                if ( tag === "*" ) {
                    while ( (elem = results[i++]) ) {
                        if ( elem.nodeType === 1 ) {
                            tmp.push( elem );
                        }
                    }
    
                    return tmp;
                }
                return results;
            };
    
        // Class
        Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
            if ( typeof context.getElementsByClassName !== strundefined && documentIsHTML ) {
                return context.getElementsByClassName( className );
            }
        };
    
        /* QSA/matchesSelector
        ---------------------------------------------------------------------- */
    
        // QSA and matchesSelector support
    
        // matchesSelector(:active) 在应该是true时会返回false (IE9/Opera 11.5)
        rbuggyMatches = [];
    
        // qSa(:focus) 在应该是true时会返回false (Chrome 21)
        rbuggyQSA = [];
    
        if ( (support.qsa = rnative.test( doc.querySelectorAll )) ) {
            assert(function( div ) {
                // Select 被有意的设置为空
                // 这是为了检测IE的行为
                div.innerHTML = "<select t=''><option selected=''></option></select>";
    
                // Support: IE8, Opera 10-12
                // 在^= 或 $= 或 *=之后如果字符串为空,应该无元素返回
                if ( div.querySelectorAll("[t^='']").length ) {
                    rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|"")" );
                }
    
                // Support: IE8
                // bool属性并没有被正确的使用
                if ( !div.querySelectorAll("[selected]").length ) {
                    rbuggyQSA.push( "\[" + whitespace + "*(?:value|" + booleans + ")" );
                }
    
                // Webkit/Opera - :checked 应该返回被选中的元素
                if ( !div.querySelectorAll(":checked").length ) {
                    rbuggyQSA.push(":checked");
                }
            });
    
            assert(function( div ) {
                // Support: Windows 8 Native Apps
                // 在设置innerHTML时,type和name的设置会被限制
                var input = doc.createElement("input");
                input.setAttribute( "type", "hidden" );
                div.appendChild( input ).setAttribute( "name", "D" );
    
                // Support: IE8
                // 增强对name的敏感程度
                if ( div.querySelectorAll("[name=d]").length ) {
                    rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
                }
    
                // FF 3.5 - :enabled/:disabled ,hidden 元素 (hidden元素仍然是enable状态)
                if ( !div.querySelectorAll(":enabled").length ) {
                    rbuggyQSA.push( ":enabled", ":disabled" );
                }
    
                // Opera 10-11 在不正确的查询下不会报错
                div.querySelectorAll("*,:x");
                rbuggyQSA.push(",.*:");
            });
        }
    
        if ( (support.matchesSelector = rnative.test( (matches = docElem.webkitMatchesSelector ||
            docElem.mozMatchesSelector ||
            docElem.oMatchesSelector ||
            docElem.msMatchesSelector) )) ) {
    
            assert(function( div ) {
                // 首先尝试下matchesSelector是否能够正常运行
                support.disconnectedMatch = matches.call( div, "div" );
    
                // 这个应该会报错
                // 在Gecko无错误,只会返回一个false
                matches.call( div, "[s!='']:x" );
                rbuggyMatches.push( "!=", pseudos );
            });
        }
    
        rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
        rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
    
        /* Contains
        ---------------------------------------------------------------------- */
        hasCompare = rnative.test( docElem.compareDocumentPosition );
    
        // 元素包含
        // 这个函数返回的值里,一个元素不会被自己包含
        contains = hasCompare || rnative.test( docElem.contains ) ?
            function( a, b ) {
                var adown = a.nodeType === 9 ? a.documentElement : a,
                    bup = b && b.parentNode;
                return a === bup || !!( bup && bup.nodeType === 1 && (
                    adown.contains ?
                        //直接用原生的contains
                        adown.contains( bup ) :
                        //或者使用compareDocumentPosition,关于&16的问题可以看下
                        //关于这个compareDocumentPosition函数的返回值
                        a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
                ));
            } :
            function( a, b ) {
                if ( b ) {
                    // 循环取b的parentNode,取到顶后会返回false
                    while ( (b = b.parentNode) ) {
                        if ( b === a ) {
                            return true;
                        }
                    }
                }
                return false;
            };
    
        /* 排序
        ---------------------------------------------------------------------- */
    
        // Document order sorting
        sortOrder = hasCompare ?
        function( a, b ) {
    
            // Flag for duplicate removal
            if ( a === b ) {
                hasDuplicate = true;
                return 0;
            }
    
            // 在a,b中只有一个有compareDocumentPosition的情况下运行,直接返回
            var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
            if ( compare ) {
                return compare;
            }
    
            // 在他们都属于一个文档下,调用compareDocumentPosition
            compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
                a.compareDocumentPosition( b ) :
    
                // 否则他们无关
                1;
    
            // 对于无关的两个node
            if ( compare & 1 ||
                // support.sortDetached对于Webkit<537.32 - Safari 6.0.3/Chrome 25的bug检测
                (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
    
                // 选择第一个和现在文档相关的元素
                if ( a === doc || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
                    return -1;
                }
                if ( b === doc || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
                    return 1;
                }
    
                // 用原有的order,这个还有点迷惑,sortInput貌似只在一个函数里用过,而且是立即销毁的
                return sortInput ?
                    ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
                    0;
            }
    
            return compare & 4 ? -1 : 1;
        } :
        function( a, b ) {
            // 元素相同就返回
            if ( a === b ) {
                hasDuplicate = true;
                return 0;
            }
    
            var cur,
                i = 0,
                aup = a.parentNode,
                bup = b.parentNode,
                ap = [ a ],
                bp = [ b ];
    
            // 如果无parent,那么不是document,就是无关的
            if ( !aup || !bup ) {
                return a === doc ? -1 :
                    b === doc ? 1 :
                    aup ? -1 :
                    bup ? 1 :
                    sortInput ?
                    ( indexOf.call( sortInput, a ) - indexOf.call( sortInput, b ) ) :
                    0;
    
            // 如果两个是sibling关系的,就直接调用siblingCheck
            } else if ( aup === bup ) {
                return siblingCheck( a, b );
            }
    
            // 否则就需要完全列出它们的祖先元素
            cur = a;
            while ( (cur = cur.parentNode) ) {
                ap.unshift( cur );
            }
            cur = b;
            while ( (cur = cur.parentNode) ) {
                bp.unshift( cur );
            }
    
            // 向下遍历直到找出分支
            while ( ap[i] === bp[i] ) {
                i++;
            }
    
            return i ?
                // 看下是否有正常的祖先元素
                siblingCheck( ap[i], bp[i] ) :
    
                // 否则节点在document外??
                ap[i] === preferredDoc ? -1 :
                bp[i] === preferredDoc ? 1 :
                0;
        };
    
        return doc;
    };

    接下来是其中的几个小函数调用,首先是support.sortDetached:

    // Support: Webkit<537.32 - Safari 6.0.3/Chrome 25
    // 侦测node对于follow混淆
    support.sortDetached = assert(function( div1 ) {
        // 应该返回1,但是返回的是4
        return div1.compareDocumentPosition( document.createElement("div") ) & 1;
    });

    然后是siblingCheck,这个函数在这篇文章的前面分析过~

    这篇就到这吧,回去搞我的毕业设计了。。。。。

  • 相关阅读:
    python实战===教你用微信每天给女朋友说晚安
    [go]beego获取参数/返回参数
    [go]os.Open方法源码
    [go]从os.Stdin探究文件类源码
    [svc]linux中的文件描述符(file descriptor)和文件
    [net]tcp和udp&socket
    [django]update_or_create使用场景
    [sh]shell语法小结
    [drf]访问文档出现错误'AutoSchema' object has no attribute 'get_link'
    [py]python操作zookeeper
  • 原文地址:https://www.cnblogs.com/cyITtech/p/3635088.html
Copyright © 2011-2022 走看看