• Sizzle.selectors.relative [ 源代码分析 ]


    1 jQuery 对象Sizzle.selectors.relative中存放了块间关系符和相应的块间关系过滤函数,称为“块间关系过滤函数集”

       块间关系符共同拥有4种,其含义和过滤方式如图所看到的。

     

    在函数Sizzle( selector, context, results, seed )从右向左进行过滤时,块间关系过滤函数被
    调用,用于检查映射集checkSet中的元素是否匹配块间关系符左側的块表达式。调用时的參
    数格式为:

    Sizzle.selectors.relative[ 块间关系符 cur  ](  映射集 checkSet,  左側块表达式pop, 
    contextXML );

    块间关系过滤函数接受3个參数:
    ‰ ‰參数checkSet:映射集,对该元素集合运行过滤操作。
    ‰ ‰參数part:大多数情况下是块间关系符左側的块表达式,该參数也能够是DOM元素。
    ‰ ‰參数isXML:布尔值,指示是否执行在一个XML文档中。
    块间关系过滤函数实现的3个关键过程例如以下:
    1)遍历映射集checkSet。
    2)依照块间关系符查找每一个元素的兄弟元素、父元素或祖先元素。
    3)检查找到的元素是否匹配參数part,并替换映射集checkSet中相应位置的元素。
    a. 假设參数part是标签,则检查找到的元素其节点名称nodeName是否与之相等,
    假设相等则替换为找到的元素,不相等则替换为false。
    b. 假设參数part是DOM元素,则检查找到的元素是否与之相等,假设相等则替换
    为true,不相等则替换为false。
    c. 假设參数part是非标签字符串,则调用方法Sizzle.filter( selector, set, inplace, not )过滤。
    也就是说,遍历结束后,映射集checkSet中的元素可能会是兄弟元素、父元素、
    祖先元素、true或false。


    1 块间关系符"+"匹配选择器"prev + next",即匹配全部紧接在元素prev后的兄弟元素
    next。比如,$("div + span")、$(".lastdiv + span")。对于从右向左的查找方式,则是检查元
    素next之前的兄弟元素是否匹配块表达式prev。

    var Expr = Sizzle.selectors = {
    	relative: {
    		"+": function(checkSet, part){
    			//检查參数是否为字符串
    			var isPartStr = typeof part === "string",
    			//指示參数part是否为标签字符串
    			isTag = isPartStr && !rNonWord.test( part ),
    			//isPartStrNotTag:指示參数part是否是非标签字符串。
    			isPartStrNotTag = isPartStr && !isTag;
    
    			if ( isTag ) {
    			part = part.toLowerCase();
    			}
    			/*
    			遍历映射集checkSet,查找每一个元素的前一个兄弟元素,并替换映
    			射集checkSet中相应位置的元素,有下面3个逻辑分支:
    			‰1 假设未找到兄弟元素,则替换为false。
    			2 ‰假设找到了兄弟元素,而且參数part是标签,则检查兄弟元素的节点名称nodeName
    			是否与之相等,假设相等则替换为兄弟元素,不相等则替换为false。
    			3 ‰假设找到了兄弟元素,而且參数part是DOM元素,则检查二者是否相等,假设相等
    			则替换为true,不相等则替换为false。
    			因此,在遍历结束后,映射集checkSet中的元素可能会是兄弟元素、true或false。
    						*/
    			for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
    				if ( (elem = checkSet[i]) ) {
    					/*在遍历兄弟元素的同一时候过滤掉非元素节点,而且仅仅要取到一个兄弟元素就
    退出while循环。*/
    					while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {
    
    					}
    
    		 			checkSet[i] = isPartStrNotTag || elem && elem.node
    					Name.toLowerCase() === part ?
    					elem || false :
    					elem === part; 
    				}
    			}
    			/*
    			假设參数part是非标签字符串,则调用方法Sizzle.filter( selector, 
    			set, inplace, not )过滤映射集checkSet。对于參数part是标签和DOM元素的情况,在前面遍
    			历映射集checkSet时已经处理过了。
    			*/
    			if ( isPartStrNotTag ) {
    				Sizzle.filter( part, checkSet, true );
    			}
    		},
    	},
    };

    2 块间关系符">"用于选择器"parent > child",即匹配父元素parent下的子元素child。
    比如,$("div + span")、$(".lastdiv + span")。对于从右向左的查找方式,则是检查子元素
    child的父元素是否匹配块表达式parent。


    var Expr = Sizzle.selectors = {
    	relative: {
    		">": function( checkSet, part ) {
    			var elem,
    			isPartStr = typeof part === "string",
    			i = 0,
    			l = checkSet.length;
    			/*
    			假设參数part是标签,则遍历映射集checkSet,查找每一个元素的
    			父元素,并检查父元素的节点名称nodeName是否与參数part相等,假设相等则替换映射集
    			checkSet中相应位置的元素为父元素,不相等则替换为false。 
    			*/
    			if ( isPartStr && !rNonWord.test( part ) ) {
    				part = part.toLowerCase();
    
    				for ( ; i < l; i++ ) {
    					elem = checkSet[i];
    
    					if ( elem ) {
    						var parent = elem.parentNode;
    						checkSet[i] = parent.nodeName.toLowerCase() === part ? 
    						parent : false;
    					}
    				}
    			} else {
    			/*
    			假设參数part不是标签,则可能是非标签字符串或DOM元素,同
    			样遍历映射集checkSet,查找每一个元素的父元素,并替换映射集checkSet中相应位置的元
    			素,在这个过程中有下面2个逻辑分支:
    			‰1 ‰假设參数part是非标签字符串,则在遍历映射集checkSet的过程中,替换映射集
    			checkSet中相应位置的元素为父元素,遍历结束后调用方法Sizzle.filter( selector, set, 
    			inplace, not )过滤映射集checkSet。
    			‰2 ‰假设參数part是元素,则在遍历映射集checkSet时,检查每一个元素的父元素是否与
    			之相等,假设相等则替换映射集checkSet中相应位置的元素为true,不相等则替换为
    			false。
    			因此,在遍历结束后,映射集checkSet中的元素可能会是父亲元素、true或false。
    			*/
    				for ( ; i < l; i++ ) {
    					elem = checkSet[i];
    
    					if ( elem ) {
    						checkSet[i] = isPartStr ?
    						elem.parentNode :
    						elem.parentNode === part;
    					}
    				}
    
    				if ( isPartStr ) {
    					Sizzle.filter( part, checkSet, true );
    				}
    			}
    		},
    	},
    };


    3 块间关系符""用于选择器"ancestor descendant",即匹配祖先元素ancestor的全部后代
    元素descendant。比如,$("div button")、$("div .btn")。对于从右向左的查找方式,则是检
    查后代元素descendant的祖先元素是否匹配块表达式ancestor。
    var Expr = Sizzle.selectors = {
    	relative: {
    		"": function(checkSet, part, isXML){
    			var nodeCheck,
    			doneName = done++,
    			checkFn = dirCheck;
    			/*
    			‰1 假设參数part是非标签字符串或DOM元素,则调用函数dirCheck()过滤映射集
    			checkSet。
    			‰2 假设參数part是标签,则调用函数dirNodeCheck()过滤映射集checkSet。
    			调用函数dirCheck()和dirNodeCheck()时的參数格式为:
    			checkFn( 方向 "parentNode/previousSibling", 块表达式 part, 缓存计数器 doneName, 映
    			射集 checkSet, nodeCheck, isXML )
    			函数dirCheck()和dirNodeCheck()会遍历映射集checkSet,查找每一个元素的祖先元素,
    			并检查是否有祖先元素匹配參数part,同一时候替换映射集checkSet中相应位置的元素。
    			*/
    			if ( typeof part === "string" && !rNonWord.test( part ) ) {
    				part = part.toLowerCase();
    				nodeCheck = part;
    				checkFn = dirNodeCheck;
    			}
    
    			checkFn( "parentNode", part, doneName, checkSet, nodeCheck, isXML );
    		},
    	},
    };


    4 块间关系符"~"用于选择器"prev~siblings",即匹配元素prev之后的全部兄弟元
    素siblings。比如,$('div~p')。对于从右向左的查找方式,则是检查元素siblings之前的
    兄弟元素是否匹配块表达式prev。
    Sizzle.selectors.relative["~"]( checkSet, part )的源代码实现与Sizzle.selectors.relative[""]
    ( checkSet, part )差点儿一样,两者的差别只在于调用函数dirCheck()和dirNodeCheck()时第
    一个參数的值不同,前者是"previousSibling",后者则是"parentNode"。
    相关代码例如以下所看到的:

    var Expr = Sizzle.selectors = {
    	relative: {
    		"~": function( checkSet, part, isXML ) {
    			var nodeCheck,
    			doneName = done++,
    			checkFn = dirCheck;
    
    			if ( typeof part === "string" && !rNonWord.test( part ) ) {
    				part = part.toLowerCase();
    				nodeCheck = part;
    				checkFn = dirNodeCheck;
    			}
    
    			checkFn( "previousSibling", part, doneName, checkSet, nodeCheck, 
    			isXML );
    		}
    	},
    };


  • 相关阅读:
    nginx 过滤了自定义的请求头参数
    Mysql5.7查看已经执行的sql语句
    Reids5 持久化
    JS 格式化时间,转成 几天前,几个月前
    个人小镜像站点
    记录一次清理Redis 病毒程序 kdevtmpfsi
    laravels 热重启
    Redis 布隆器安装和简单实现
    Redis Zset类型跳跃表算法实现(JAVA)
    Redis5 基于Lua实现分布式排它锁
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/4057492.html
Copyright © 2020-2023  润新知