jQuery.API源码深入剖析以及应用实现(3) - 选择器篇(上)
2009-02-21 11:10
976 查看
还漏了一个框题,jQuery的冲突机制解决方法jQuery.noConflict()以及jQuery.noConflict(extreme),这里先分析一下:
jQuery.noConflict():运行这个函数将变量$的控制权让渡给第一个实现它的那个库。
jQuery.noConflict(extreme):将$和jQuery的控制权都交还给原来的库。
比如在prototype框架中的$会和jQuery框架中的$产生命名冲突,这里就是为了解决这种问题。
现在先看下noConflict方法的具体实现:
noConflict: function( deep ) {
window.$ = _$;
if ( deep )
window.jQuery = _jQuery;
return jQuery;
}
其中_$,_jQuery是在jQquery源码的开始几行定义的:
(function(){
var
// Code
其中set = Sizzle.filter( ret.expr, ret.set );调用Sizzle.filter方法:
Sizzle.filter = function(expr, set, inplace, not){
var old = expr, result = [], curLoop = set, match, anyFound;
while ( expr && set.length ) {
for ( var type in Expr.filter ) {
if ( (match = Expr.match[ type ].exec( expr )) != null ) {
var filter = Expr.filter[ type ], found, item;
anyFound = false;
if ( curLoop == result ) {
result = [];
}
if ( Expr.preFilter[ type ] ) {
match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not );
if ( !match ) {
anyFound = found = true;
} else if ( match === true ) {
continue;
}
}
if ( match ) {
for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
if ( item ) {
found = filter( item, match, i, curLoop );
var pass = not ^ !!found;
if ( inplace && found != null ) {
if ( pass ) {
anyFound = true;
} else {
curLoop[i] = false;
}
} else if ( pass ) {//$("form input")从这里进
result.push( item );
anyFound = true;
}
}
}
}
if ( found !== undefined ) {
if ( !inplace ) {
curLoop = result;
}
expr = expr.replace( Expr.match[ type ], "" );
if ( !anyFound ) {
return [];
}
break;
}
}
}
expr = expr.replace(/"s*,"s*/, "");
// Improper expression
if ( expr == old ) {
if ( anyFound == null ) {
throw "Syntax error, unrecognized expression: " + expr;
} else {
break;
}
}
old = expr;
}
return curLoop;
};
最关键是在加粗字代码,result.push( item ); anyFound = true; 和 curLoop = result;将匹配的元素加入result中,然后赋值于curLoop。
而方法的最后返回的是curLoop。所匹配的元素就是最后所需要的jQuery对象。
2. 【parent > child】
在给定的父元素下匹配所有的子元素。
我们只要查看一下它的核心代码:
relative: {
//
">": function(checkSet, part, isXML){
// 当part为单词字符时,如$("form > input"),part为“form”
if ( typeof part === "string" && !/"W/.test(part) ) {
part = isXML ? part : part.toUpperCase();
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
var elem = checkSet[i];
if ( elem ) {
// 得到elem的父节点
var parent = elem.parentNode;
// 如果父节点名称为part值时,在checkSet[i]上赋值父节点,否则赋值false
checkSet[i] = parent.nodeName === part ? parent : false;
}
}
// 当part为非单词字符时,如$(".blue > input"),part为“.blue”
} else {
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
var elem = checkSet[i];
if ( elem ) {
checkSet[i] = typeof part === "string" ?
elem.parentNode :
elem.parentNode === part;
}
}
if ( typeof part === "string" ) {
Sizzle.filter( part, checkSet, true );
}
}
},
}
从这里我们可以得到checkSet的值集合。
2. 【prev + next】
匹配所有紧接在 prev 元素后的 next 元素。next (Selector) :一个有效选择器并且紧接着第一个选择器。
例子
只要查看一下它的核心代码:
relative: {
//
"+": function(checkSet, part){
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
var elem = checkSet[i];
if ( elem ) {
// 得到elem的前一个节点
var cur = elem.previousSibling;
// 当cur的节点类型不为元素节点的时候,继续得到cur的前一个节点,否则循环结束
while ( cur && cur.nodeType !== 1 ) {
cur = cur.previousSibling;
}
checkSet[i] = typeof part === "string" ?
cur || false :
cur === part;
}
}
if ( typeof part === "string" ) {
Sizzle.filter( part, checkSet, true );
}
},
//
}
从这里我们可以得到checkSet的值集合。
3. 【prev ~ next】
匹配 prev 元素之后的所有 siblings 元素。
例子
只要查看一下它的核心代码:
relative: {
//
"~": function(checkSet, part, isXML){
var doneName = "done" + (done++), checkFn = dirCheck;
if ( typeof part === "string" && !part.match(/"W/) ) {
var nodeCheck = part = isXML ? part : part.toUpperCase();
checkFn = dirNodeCheck;
}
checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
}
}
其中checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); 调用的是dirCheck方法,它的具体实现为:
function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
var elem = checkSet[i];
if ( elem ) {
elem = elem[dir];
var match = false;
while ( elem && elem.nodeType ) {
if ( elem[doneName] ) {
match = checkSet[ elem[doneName] ];
break;
}
if ( elem.nodeType === 1 ) {
if ( !isXML )
elem[doneName] = i;
if ( typeof cur !== "string" ) {
if ( elem === cur ) {
match = true;
break;
}
} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
match = elem;
break;
}
}
// 由于这里dir为previousSibling,所以这里利用循环不断得到elem的前一个节点,并且赋值checkSet数组
elem = elem[dir];
}
checkSet[i] = match;
}
}
}
从这里我们可以得到checkSet的值集合。
三、简单
1. 【:first】,【:last】,【:even】,【:odd】,【 :eq(index) 】,【 :gt(index) 】,【 :lt(index) 】和 【 :not(selector) 】
:first 匹配找到的第一个元素。
:last 匹配找到的最后一个元素。
:even 匹配所有索引值为偶数的元素,从 0 开始计数。
:odd 匹配所有索引值为奇数的元素,从 0 开始计数。
:eq(index) 匹配一个给定索引值的元素。
:gt(index) 匹配所有大于给定索引值的元素。
:lt(index) 匹配所有小于给定索引值的元素。
:not(selector) 去除所有与给定选择器匹配的元素。
例子
首先我们看下它的一个正则表达式:
POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:"(("d*)"))?(?=[^-]|$)/,
核心代码从Sizzle.filter开始:
让我们先看下var filter = Expr.filter[ type ],的Expr.filter的具体实现,核心代码为:
接着看下Expr.setFilters的具体实现:
setFilters: {
first: function(elem, i){
return i === 0;
},
last: function(elem, i, match, array){
return i === array.length - 1;
},
even: function(elem, i){
return i % 2 === 0;
},
odd: function(elem, i){
return i % 2 === 1;
},
lt: function(elem, i, match){
return i < match[3] - 0;
},
gt: function(elem, i, match){
return i > match[3] - 0;
},
nth: function(elem, i, match){
return match[3] - 0 == i;
},
eq: function(elem, i, match){
return match[3] - 0 == i;
}
}
噢,所有的标识 主要在这里判断elem元素在集合中的逻辑位置,并且返回一个布尔值。
接着 match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not ); Expr.prefilter的具体实现,主要核心代码为:
PSEUDO: function(match, curLoop, inplace, result, not){
if ( match[1] === "not" ) {
// 代码1
if ( match[3].match(chunker).length > 1 ) {
match[3] = Sizzle(match[3], null, null, curLoop);
} else {
var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
if ( !inplace ) {
result.push.apply( result, ret );
}
return false;
}
} else if ( Expr.match.POS.test( match[0] ) ) {
return true;
}
return match;
}
当match[1]匹配中包含为“not”时,即表达式字符串中包含:not时,发生“代码1”;否则,根据POS的正则表达式判断返回true。
最后将匹配的item元素入栈,即 result.push( item )。Sizzle.filter最后返回的是curLoop。所匹配的元素就是最后所需要的jQuery对象。
jQuery.noConflict():运行这个函数将变量$的控制权让渡给第一个实现它的那个库。
jQuery.noConflict(extreme):将$和jQuery的控制权都交还给原来的库。
比如在prototype框架中的$会和jQuery框架中的$产生命名冲突,这里就是为了解决这种问题。
现在先看下noConflict方法的具体实现:
noConflict: function( deep ) {
window.$ = _$;
if ( deep )
window.jQuery = _jQuery;
return jQuery;
}
其中_$,_jQuery是在jQquery源码的开始几行定义的:
(function(){
var
// Code
其中set = Sizzle.filter( ret.expr, ret.set );调用Sizzle.filter方法:
Sizzle.filter = function(expr, set, inplace, not){
var old = expr, result = [], curLoop = set, match, anyFound;
while ( expr && set.length ) {
for ( var type in Expr.filter ) {
if ( (match = Expr.match[ type ].exec( expr )) != null ) {
var filter = Expr.filter[ type ], found, item;
anyFound = false;
if ( curLoop == result ) {
result = [];
}
if ( Expr.preFilter[ type ] ) {
match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not );
if ( !match ) {
anyFound = found = true;
} else if ( match === true ) {
continue;
}
}
if ( match ) {
for ( var i = 0; (item = curLoop[i]) != null; i++ ) {
if ( item ) {
found = filter( item, match, i, curLoop );
var pass = not ^ !!found;
if ( inplace && found != null ) {
if ( pass ) {
anyFound = true;
} else {
curLoop[i] = false;
}
} else if ( pass ) {//$("form input")从这里进
result.push( item );
anyFound = true;
}
}
}
}
if ( found !== undefined ) {
if ( !inplace ) {
curLoop = result;
}
expr = expr.replace( Expr.match[ type ], "" );
if ( !anyFound ) {
return [];
}
break;
}
}
}
expr = expr.replace(/"s*,"s*/, "");
// Improper expression
if ( expr == old ) {
if ( anyFound == null ) {
throw "Syntax error, unrecognized expression: " + expr;
} else {
break;
}
}
old = expr;
}
return curLoop;
};
最关键是在加粗字代码,result.push( item ); anyFound = true; 和 curLoop = result;将匹配的元素加入result中,然后赋值于curLoop。
而方法的最后返回的是curLoop。所匹配的元素就是最后所需要的jQuery对象。
2. 【parent > child】
在给定的父元素下匹配所有的子元素。
HTML代码 | jQuery代码 | 结果 |
<form> <label>Name:</label> <input name="name" /> <fieldset> <label>Newsletter:</label> <input name="newsletter" /> </fieldset> </form> <input name="none" /> | $("form > input") | [ <input name="name" /> ] |
relative: {
//
">": function(checkSet, part, isXML){
// 当part为单词字符时,如$("form > input"),part为“form”
if ( typeof part === "string" && !/"W/.test(part) ) {
part = isXML ? part : part.toUpperCase();
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
var elem = checkSet[i];
if ( elem ) {
// 得到elem的父节点
var parent = elem.parentNode;
// 如果父节点名称为part值时,在checkSet[i]上赋值父节点,否则赋值false
checkSet[i] = parent.nodeName === part ? parent : false;
}
}
// 当part为非单词字符时,如$(".blue > input"),part为“.blue”
} else {
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
var elem = checkSet[i];
if ( elem ) {
checkSet[i] = typeof part === "string" ?
elem.parentNode :
elem.parentNode === part;
}
}
if ( typeof part === "string" ) {
Sizzle.filter( part, checkSet, true );
}
}
},
}
从这里我们可以得到checkSet的值集合。
2. 【prev + next】
匹配所有紧接在 prev 元素后的 next 元素。next (Selector) :一个有效选择器并且紧接着第一个选择器。
例子
HTML代码 | jQuery代码 | 结果 |
<form> <label>Name:</label> <input name="name" /> <fieldset> <label>Newsletter:</label> <input name="newsletter" /> </fieldset> </form> <input name="none" /> | $("label + input") | [ <input name="name" />, <input name="newsletter" /> ] |
relative: {
//
"+": function(checkSet, part){
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
var elem = checkSet[i];
if ( elem ) {
// 得到elem的前一个节点
var cur = elem.previousSibling;
// 当cur的节点类型不为元素节点的时候,继续得到cur的前一个节点,否则循环结束
while ( cur && cur.nodeType !== 1 ) {
cur = cur.previousSibling;
}
checkSet[i] = typeof part === "string" ?
cur || false :
cur === part;
}
}
if ( typeof part === "string" ) {
Sizzle.filter( part, checkSet, true );
}
},
//
}
从这里我们可以得到checkSet的值集合。
3. 【prev ~ next】
匹配 prev 元素之后的所有 siblings 元素。
例子
HTML代码 | jQuery代码 | 结果 |
<form> <label>Name:</label> <input name="name" /> <fieldset> <label>Newsletter:</label> <input name="newsletter" /> </fieldset> </form> <input name="none" /> <input name="none2" /> | $("form ~ input") | [ <input name="none" />, <input name="none2" />] |
relative: {
//
"~": function(checkSet, part, isXML){
var doneName = "done" + (done++), checkFn = dirCheck;
if ( typeof part === "string" && !part.match(/"W/) ) {
var nodeCheck = part = isXML ? part : part.toUpperCase();
checkFn = dirNodeCheck;
}
checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML);
}
}
其中checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); 调用的是dirCheck方法,它的具体实现为:
function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
var elem = checkSet[i];
if ( elem ) {
elem = elem[dir];
var match = false;
while ( elem && elem.nodeType ) {
if ( elem[doneName] ) {
match = checkSet[ elem[doneName] ];
break;
}
if ( elem.nodeType === 1 ) {
if ( !isXML )
elem[doneName] = i;
if ( typeof cur !== "string" ) {
if ( elem === cur ) {
match = true;
break;
}
} else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {
match = elem;
break;
}
}
// 由于这里dir为previousSibling,所以这里利用循环不断得到elem的前一个节点,并且赋值checkSet数组
elem = elem[dir];
}
checkSet[i] = match;
}
}
}
从这里我们可以得到checkSet的值集合。
三、简单
1. 【:first】,【:last】,【:even】,【:odd】,【 :eq(index) 】,【 :gt(index) 】,【 :lt(index) 】和 【 :not(selector) 】
:first 匹配找到的第一个元素。
:last 匹配找到的最后一个元素。
:even 匹配所有索引值为偶数的元素,从 0 开始计数。
:odd 匹配所有索引值为奇数的元素,从 0 开始计数。
:eq(index) 匹配一个给定索引值的元素。
:gt(index) 匹配所有大于给定索引值的元素。
:lt(index) 匹配所有小于给定索引值的元素。
:not(selector) 去除所有与给定选择器匹配的元素。
例子
HTML代码 | jQuery代码 |
<table> <tr><td>Header 1</td></tr> <tr><td>Value 1</td></tr> <tr><td>Value 2</td></tr> </table> | $("tr:first"),$("tr:last"),$("tr:even"),$("tr:odd"),$("tr:eq(1)"),$("tr:gt(0)") |
POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:"(("d*)"))?(?=[^-]|$)/,
核心代码从Sizzle.filter开始:
让我们先看下var filter = Expr.filter[ type ],的Expr.filter的具体实现,核心代码为:
接着看下Expr.setFilters的具体实现:
setFilters: {
first: function(elem, i){
return i === 0;
},
last: function(elem, i, match, array){
return i === array.length - 1;
},
even: function(elem, i){
return i % 2 === 0;
},
odd: function(elem, i){
return i % 2 === 1;
},
lt: function(elem, i, match){
return i < match[3] - 0;
},
gt: function(elem, i, match){
return i > match[3] - 0;
},
nth: function(elem, i, match){
return match[3] - 0 == i;
},
eq: function(elem, i, match){
return match[3] - 0 == i;
}
}
噢,所有的标识 主要在这里判断elem元素在集合中的逻辑位置,并且返回一个布尔值。
接着 match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not ); Expr.prefilter的具体实现,主要核心代码为:
PSEUDO: function(match, curLoop, inplace, result, not){
if ( match[1] === "not" ) {
// 代码1
if ( match[3].match(chunker).length > 1 ) {
match[3] = Sizzle(match[3], null, null, curLoop);
} else {
var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);
if ( !inplace ) {
result.push.apply( result, ret );
}
return false;
}
} else if ( Expr.match.POS.test( match[0] ) ) {
return true;
}
return match;
}
当match[1]匹配中包含为“not”时,即表达式字符串中包含:not时,发生“代码1”;否则,根据POS的正则表达式判断返回true。
最后将匹配的item元素入栈,即 result.push( item )。Sizzle.filter最后返回的是curLoop。所匹配的元素就是最后所需要的jQuery对象。
相关文章推荐
- jQuery.API源码深入剖析以及应用实现(3) - 选择器篇(上)
- jQuery.API源码深入剖析以及应用实现(4) - 选择器篇(下)
- jQuery.API源码深入剖析以及应用实现(4) - 选择器篇(下)
- jQuery.API源码深入剖析以及应用实现(4) - 选择器篇(下)
- jQuery.API源码深入剖析以及应用实现(1) - 核心函数篇
- jQuery.API源码深入剖析以及应用实现(2) - jQuery对象访问和数据缓存
- jQuery.API源码深入剖析以及应用实现(1) - 核心函数篇
- jQuery.API源码深入剖析以及应用实现(1) - 核心函数篇
- jQuery.API源码深入剖析以及应用实现(1) - 核心函数篇
- jQuery.API源码深入剖析以及应用实现(2) - jQuery对象访问和数据缓存
- jQuery.API源码深入剖析以及应用实现(1) - 核心函数篇(1)
- jQuery.API源码深入剖析以及应用实现(4) - 选择器篇(下)
- jQuery.API源码深入剖析以及应用实现(2) - jQuery对象访问和数据缓存
- 深入剖析Spring Web源码(九) - 处理器映射,处理器适配器以及处理器的实现 - 基于注解控制器流程的实现
- 深入剖析Spring Web源码(十一) - 处理器映射,处理器适配器以及处理器的实现 - 处理器映射的实现架构
- 深入剖析Spring Web源码(十一) - 处理器映射,处理器适配器以及处理器的实现 - 处理器映射的实现架构
- 深入剖析Spring Web源码(十) - 处理器映射,处理器适配器以及处理器的实现 - 基于HTTP请求处理器流程的实现
- 深入剖析Spring Web源码(十四) - 处理器映射,处理器适配器以及处理器的实现 - 处理器的实现架构 - 注解控制器
- 深入剖析Spring Web源码(十六) - 处理器映射,处理器适配器以及处理器的实现 - 拦截器的实现架构
- 深入剖析Spring Web源码(八) - 处理器映射,处理器适配器以及处理器的实现 - 基于简单控制器流程的实现