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,这个函数在这篇文章的前面分析过~

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

  • 相关阅读:
    215. Kth Largest Element in an Array
    214. Shortest Palindrome
    213. House Robber II
    212. Word Search II
    210 Course ScheduleII
    209. Minimum Size Subarray Sum
    208. Implement Trie (Prefix Tree)
    207. Course Schedule
    206. Reverse Linked List
    sql 开发经验
  • 原文地址:https://www.cnblogs.com/cyITtech/p/3635088.html
Copyright © 2011-2022 走看看