- 浏览: 1316349 次
- 性别:
- 来自: 成都
文章分类
- 全部博客 (471)
- 原创文章 (4)
- Database (84)
- J2SE (63)
- Web (26)
- Javascript (30)
- Lucene (11)
- os (13)
- 算法 (8)
- Webservice (1)
- Open projects (18)
- Hibernate (18)
- Spring (15)
- Css (2)
- J2ee (2)
- 综合技术 (18)
- 安全管理 (13)
- PatternsInJava (27)
- NIO (5)
- Ibatis (2)
- 书籍收藏 (1)
- quartz (7)
- 并发编程 (15)
- oracle问题 (2)
- ios (60)
- coco2d-iphone (3)
- C++ (6)
- Zookeeper (2)
- golang (4)
- animation (2)
- android (1)
最新评论
-
dandingge123:
【引用】限制UITextField输入长度的方法 -
qja:
...
对List顺序,逆序,随机排列实例代码 -
安静听歌:
现在在搞这个,,,,,哎~头都大了,,,又freemarker ...
通用大型网站页面静态化解决方案(一) -
springdata-jpa:
java quartz定时任务demo教程源代码下载,地址:h ...
Quartz 配置参考 -
马清天:
[b][/b][list][*]引用[u][/u][/list ...
通用大型网站页面静态化解决方案(一)
做网站免不了用到JS,如果大量用到选择一个JS框架是个不错的选择,今天我就抛砖引玉说说jQuery的选择器,了解它的原理是提高效率的最佳途径。每当你看到jQuery独特的语法时是否有想过它是如何实现的呢?是否觉得相当复杂让你都不敢去想呢,今天就让我们揭开jQuery选择器的神秘面纱。
一、选择器入口
var Utils = {
find : function (expr,context){
return selector.quick(expr,context || document);
}
}
expr就是表达式了,如下(注:我所说的都是jQuery的原理):
代码
//效率最高,直接映射到document.getElementById
Utils.find("#id")
//支持querySelectorAll否则调用context.getElementsByName然后遍历getAttribute("name")等于a的
Utils.find("input[name=a]")
//不支持querySelectorAll,调用context.getElementsByName然后遍历getAttribute("name")等于a的,然后筛选出选中的
Utils.find("input:checked[name=a]")
//支持querySelectorAll否则映射到context.getElementsByTagName
Utils.find("input")
//支持querySelectorAll否则调用context.getElementsByTagName("*")然后筛选出className包含className的标签
Utils.find(".cssName")
context 上下文哦,主要是在这个里面查找哦
代码
var selector = {};
selector.quick = function(expr,context){
//#id
if( /^#([\w-]+)$/.test( expr ) ){
return context.getElementById( expr.substr(1) );
}
//TAG
else if ( /^\w+$/.test( expr ) ) {
return selector.array( context.getElementsByTagName( expr ));
}
try
{
return selector.array(context.querySelectorAll(expr));//ie6 ie7都不支持哦
}catch(e) {}
return selector.array(selector(expr,context,isXML(context)));//不支持就只能用最原始的啦
}
querySelectorAll
是什么?这个可是主角啊,jQuery独特的语法其实就是参考自它的,标准且主流的浏览器都支持了,比如ie8,ff等等,然而ie6、ie7都不支持哦,所以我们需要自己来实现,后面很多代码其实都是为了解决不支持它而写的,可恨啊。。。
查看资料:
http://www.w3.org/TR/selectors-api/
http://www.w3.org/TR/css3-selectors/
http://msdn.microsoft.com/zh-cn/library/cc304114(en-us,VS.85).aspx
看看document.querySelectorAll都支持什么语法
代码
var a = document.querySelectorAll("#a, #b, #c");
var b = document.querySelectorAll("#frm p #a");
var c = document.querySelectorAll("body p.cssName");
var d = document.querySelectorAll("p.abc, #a");
var e = document.querySelectorAll("input");
var f = document.querySelector("body p[id=aa] span");
var g = document.querySelectorAll("ul.nav>li");
var h = document.querySelectorAll("input[checked=checked]");
//.....
二、选择器实现
代码
var selector = function(expr, context, isXML){
var set, match;
if ( !expr ) {
return [];
}
for ( var i = 0, l = Expr.order.length; i < l; i++ ) {
var type = Expr.order[i], match;
if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {
var left = match[1];
match.splice(1,1);
if ( left.substr( left.length - 1 ) !== "\\" ) {
match[1] = (match[1] || "").replace(/\\/g, "");
set = Expr.find[ type ]( match, context, isXML );
if ( set != null ) {
expr = expr.replace( Expr.match[ type ], "" );
break;
}
}
}
}
if ( !set ) {
set =
context.getElementsByTagName("*");//效率非常低下,获取所有的标签,然后调用filter筛选出需要的
}
return filter(expr,set);
};
selector.array = function(array){
var ret = [];
if ( Object.prototype.toString.call(array) === "[object Array]" ) {
Array.prototype.push.apply( ret, array );
} else {
if ( typeof array.length === "number" ) {
for ( var i = 0, l = array.length; i < l; i++ ) {
ret.push( array[i] );
}
} else {
for ( var i = 0; array[i]; i++ ) {
ret.push( array[i] );
}
}
}
return ret;
}
//判断是否是xml
var isXML = function(elem){
// documentElement is verified for cases where it doesn't yet exist
// (such as loading iframes in IE - #4833)
var documentElement = (elem ? elem.ownerDocument || elem :
0).documentElement;
return documentElement ? documentElement.nodeName !== "HTML" : false;
};
其实上面都实现大半了,下面会有很多代码其实都是为了解决不支持querySelectorAll 而写的。看代码吧,其实不难。
代码
var Expr = {
order: [ "ID", "NAME", "TAG" ],
match: {
ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/,
NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/,
ATTR:
/\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,
TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/,
CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/,
POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/,
PSEUDO:
/:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/
},
leftMatch: {},
attrMap: {
"class": "className",
"for": "htmlFor"
},
attrHandle: {
href: function(elem){
return elem.getAttribute("href");
}
},
relative: {
"+": function(checkSet, part){
var isPartStr = typeof part === "string",
isTag = isPartStr && !/\W/.test(part),
isPartStrNotTag = isPartStr && !isTag;
if ( isTag ) {
part = part.toLowerCase();
}
for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {
if ( (elem = checkSet[i]) ) {
while ( (elem = elem.previousSibling) && elem.nodeType !== 1
) {}
checkSet[i] = isPartStrNotTag || elem &&
elem.nodeName.toLowerCase() === part ?
elem || false :
elem === part;
}
}
if ( isPartStrNotTag ) {
Sizzle.filter( part, checkSet, true );
}
},
">": function(checkSet, part){
var isPartStr = typeof part === "string";
if ( isPartStr && !/\W/.test(part) ) {
part = part.toLowerCase();
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
var elem = checkSet[i];
if ( elem ) {
var parent = elem.parentNode;
checkSet[i] = parent.nodeName.toLowerCase() === part ?
parent : false;
}
}
} else {
for ( var i = 0, l = checkSet.length; i < l; i++ ) {
var elem = checkSet[i];
if ( elem ) {
checkSet[i] = isPartStr ?
elem.parentNode :
elem.parentNode === part;
}
}
if ( isPartStr ) {
Sizzle.filter( part, checkSet, true );
}
}
},
"": function(checkSet, part, isXML){
var doneName = done++, checkFn = dirCheck;
if ( typeof part === "string" && !/\W/.test(part) ) {
var nodeCheck = part = part.toLowerCase();
checkFn = dirNodeCheck;
}
checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML);
},
"~": function(checkSet, part, isXML){
var doneName = done++, checkFn = dirCheck;
if ( typeof part === "string" && !/\W/.test(part) ) {
var nodeCheck = part = part.toLowerCase();
checkFn = dirNodeCheck;
}
checkFn("previousSibling", part, doneName, checkSet, nodeCheck,
isXML);
}
},
find: {
ID: function(match, context, isXML){
if ( typeof context.getElementById !== "undefined" && !isXML ) {
var m = context.getElementById(match[1]);
return m ? [m] : [];
}
},
NAME: function(match, context){
if ( typeof context.getElementsByName !== "undefined" ) {
var ret = [], results = context.getElementsByName(match[1]);
for ( var i = 0, l = results.length; i < l; i++ ) {
if ( results[i].getAttribute("name") === match[1] ) {
ret.push( results[i] );
}
}
return ret.length === 0 ? null : ret;
}
},
TAG: function(match, context){
return context.getElementsByTagName(match[1]);
}
},
preFilter: {
CLASS: function(match, curLoop, inplace, result, not, isXML){
match = " " + match[1].replace(/\\/g, "") + " ";
if ( isXML ) {
return match;
}
for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {
if ( elem ) {
if ( not ^ (elem.className && (" " + elem.className + "
").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) {
if ( !inplace ) {
result.push( elem );
}
} else if ( inplace ) {
curLoop[i] = false;
}
}
}
return false;
},
ID: function(match){
return match[1].replace(/\\/g, "");
},
TAG: function(match, curLoop){
return match[1].toLowerCase();
},
CHILD: function(match){
if ( match[1] === "nth" ) {
// parse equations like 'even', 'odd', '5', '2n', '3n+2',
'4n-1', '-n+6'
var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec(
match[2] === "even" && "2n" || match[2] === "odd" && "2n+1"
||
!/\D/.test( match[2] ) && "0n+" + match[2] || match[2]);
// calculate the numbers (first)n+(last) including if they are
negative
match[2] = (test[1] + (test[2] || 1)) - 0;
match[3] = test[3] - 0;
}
// TODO: Move to normal caching system
match[0] = done++;
return match;
},
ATTR: function(match, curLoop, inplace, result, not, isXML){
var name = match[1].replace(/\\/g, "");
if ( !isXML && Expr.attrMap[name] ) {
match[1] = Expr.attrMap[name];
}
if ( match[2] === "~=" ) {
match[4] = " " + match[4] + " ";
}
return match;
},
PSEUDO: function(match, curLoop, inplace, result, not){
if ( match[1] === "not" ) {
// If we're dealing with a complex expression, or a simple one
if ( ( chunker.exec(match[3]) || "" ).length > 1 ||
/^\w/.test(match[3]) ) {
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] ) ||
Expr.match.CHILD.test( match[0] ) ) {
return true;
}
return match;
},
POS: function(match){
match.unshift( true );
return match;
}
},
filters: {
enabled: function(elem){
return elem.disabled === false && elem.type !== "hidden";
},
disabled: function(elem){
return elem.disabled === true;
},
checked: function(elem){
return elem.checked === true;
},
selected: function(elem){
// Accessing this property makes selected-by-default
// options in Safari work properly
elem.parentNode.selectedIndex;
return elem.selected === true;
},
parent: function(elem){
return !!elem.firstChild;
},
empty: function(elem){
return !elem.firstChild;
},
has: function(elem, i, match){
return !!Sizzle( match[3], elem ).length;
},
header: function(elem){
return /h\d/i.test( elem.nodeName );
},
text: function(elem){
return "text" === elem.type;
},
radio: function(elem){
return "radio" === elem.type;
},
checkbox: function(elem){
return "checkbox" === elem.type;
},
file: function(elem){
return "file" === elem.type;
},
password: function(elem){
return "password" === elem.type;
},
submit: function(elem){
return "submit" === elem.type;
},
image: function(elem){
return "image" === elem.type;
},
reset: function(elem){
return "reset" === elem.type;
},
button: function(elem){
return "button" === elem.type || elem.nodeName.toLowerCase() ===
"button";
},
input: function(elem){
return /input|select|textarea|button/i.test(elem.nodeName);
}
},
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;
}
},
filter: {
PSEUDO: function(elem, match, i, array){
var name = match[1], filter = Expr.filters[ name ];
if ( filter ) {
return filter( elem, i, match, array );
} else if ( name === "contains" ) {
return (elem.textContent || elem.innerText || getText([ elem ])
|| "").indexOf(match[3]) >= 0;
} else if ( name === "not" ) {
var not = match[3];
for ( var i = 0, l = not.length; i < l; i++ ) {
if ( not[i] === elem ) {
return false;
}
}
return true;
} else {
Sizzle.error( "Syntax error, unrecognized expression: " + name
);
}
},
CHILD: function(elem, match){
var type = match[1], node = elem;
switch (type) {
case 'only':
case 'first':
while ( (node = node.previousSibling) ) {
if ( node.nodeType === 1 ) {
return false;
}
}
if ( type === "first" ) {
return true;
}
node = elem;
case 'last':
while ( (node = node.nextSibling) ) {
if ( node.nodeType === 1 ) {
return false;
}
}
return true;
case 'nth':
var first = match[2], last = match[3];
if ( first === 1 && last === 0 ) {
return true;
}
var doneName = match[0],
parent = elem.parentNode;
if ( parent && (parent.sizcache !== doneName ||
!elem.nodeIndex) ) {
var count = 0;
for ( node = parent.firstChild; node; node =
node.nextSibling ) {
if ( node.nodeType === 1 ) {
node.nodeIndex = ++count;
}
}
parent.sizcache = doneName;
}
var diff = elem.nodeIndex - last;
if ( first === 0 ) {
return diff === 0;
} else {
return ( diff % first === 0 && diff / first >= 0 );
}
}
},
ID: function(elem, match){
return elem.nodeType === 1 && elem.getAttribute("id") === match;
},
TAG: function(elem, match){
return (match === "*" && elem.nodeType === 1) ||
elem.nodeName.toLowerCase() === match;
},
CLASS: function(elem, match){
return (" " + (elem.className || elem.getAttribute("class")) + " ")
.indexOf( match ) > -1;
},
ATTR: function(elem, match){
var name = match[1],
result = Expr.attrHandle[ name ] ?
Expr.attrHandle[ name ]( elem ) :
elem[ name ] != null ?
elem[ name ] :
elem.getAttribute( name ),
value = result + "",
type = match[2],
check = match[4];
return result == null ?
type === "!=" :
type === "=" ?
value === check :
type === "*=" ?
value.indexOf(check) >= 0 :
type === "~=" ?
(" " + value + " ").indexOf(check) >= 0 :
!check ?
value && result !== false :
type === "!=" ?
value !== check :
type === "^=" ?
value.indexOf(check) === 0 :
type === "$=" ?
value.substr(value.length - check.length) === check :
type === "|=" ?
value === check || value.substr(0, check.length + 1) === check +
"-" :
false;
},
POS: function(elem, match, i, array){
var name = match[2], filter = Expr.setFilters[ name ];
if ( filter ) {
return filter( elem, i, match, array );
}
}
}
};
for ( var type in Expr.match ) {
Expr.match[ type ] = new RegExp( Expr.match[ type ].source +
/(?![^\[]*\])(?![^\(]*\))/.source );
Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[
type ].source.replace(/\\(\d+)/g, function(all, num){
return "\\" + (num - 0 + 1);
}));
}
jQuery 不是获取的多个元素可以each遍历么?看看如何实现哦
代码
if (!Object.prototype.each) {
Array.prototype.each = function (fn) {
if ( this.length > 0 ) {
for ( var i = 0; i < this.length; i++ ) {
fn.call( this[i], i );
}
}
}
}
发表评论
-
关闭输入框自动完成 firefox msie disable input autocomplete
2010-10-28 10:43 3095English Title:Shut input casing ... -
js中prototype用法
2010-10-20 15:56 1239prototype 是在 IE 4 及其以后版本引入的一个 ... -
jquery source
2010-10-20 15:03 1161http://tech.ddvip.com/2009-01/1 ... -
使用 JavaScript 拦截和跟踪浏览器中的 HTTP 请求
2010-10-20 14:10 3760HTTP 请求的拦截技术可以广泛地应用在反向代理、拦截 Aja ... -
监听输入框值的即时变
2010-10-20 12:34 1612写道 <html> <head> ... -
判断上传文件的大小
2010-10-19 12:44 1328var Sys = {}; if ... -
js继承的实现
2010-10-19 11:16 1102写道 js继承有5种实现方式: 1、继承第一种方式:对象 ... -
js面向对象
2010-10-19 11:15 2531写道 1、js区别于java的特性还有:实例化类对象时,如 ... -
js高级进阶
2010-10-19 11:14 8134写道 1、js不支持函数(方法)的重载 2、js中,一个 ... -
jQuery 简但实现select二级联动
2010-08-23 12:09 4730写道 < !DOCTYPE html PUBLIC ... -
原始的Ajax 直接使用XmlHttpRequest
2010-08-23 11:29 1869写道 //定义XMLHttp实例 var xmlHttp ... -
jquery checkbox,radio ,select value
2010-08-12 10:01 1595写道 .date-region select:visi ... -
jquery flot 使用笔记
2010-06-27 00:57 5771写道 <!DOCTYPE HTML PUBLIC &q ... -
js clone
2010-05-13 13:50 1259<!DOCTYPE html PUBLIC &q ... -
javascript可以轻松操作客户端剪贴板内容
2010-04-19 12:29 1333写道 <html> <head> ... -
dhtml
2010-04-09 10:18 2352写道 Object.__defineGetter__ = ... -
MzTreeView
2010-03-24 16:05 5633写道 MzTreeView 1.0 是数据一次性加载,客户 ... -
JavaScript 节点操作 以及DOMDocument属性和方法
2010-03-24 15:28 15931Attributes 存储节点的属 ... -
在网页里打开本地的驱动器
2010-03-24 12:14 1553<html> <head> < ... -
页面登录进度条
2010-03-24 12:13 1594<form name=loading> < ...
相关推荐
这个函数接收一个包含 CSS 选择器的字符串,然后用这个字符串去匹配一组元素。 jQuery 的核心功能都是通过这个函数实现的。 jQuery中的一切都构建于这个函数之上,或者说都是在以某种方式使用这个函数。这个函数最...
提示:jQuery 使用的语法是 XPath 与 CSS 选择器语法的组合。在本教程接下来的章节,您将学习到更多有关选择器的语法。 文档就绪函数 您也许已经注意到在我们的实例中的所有 jQuery 函数位于一个 document ready ...
本套Java视频教程循序渐进地对jQuery的各种选择器、函数和方法调用进行了详细的讲解,更结合了大量的案例进行分析。001_动力节点_jQuery视频 资源太大,传百度网盘了,链接在附件中,有需要的同学自取。
jQuery 中选择器表达式让你找到页面上所有的元素,你将会使用选择器表达 式来样式化页面上不同的元素,有时候可以不是纯 css。 在第三章里,你会学习如何触发事件,浏览器发事件时,你将会使用 jQuery 的事件处理机 ...
#jquery#location-picker,#maps,#autocomplete,#geocode,#OpenStreetMap,#OSM,#OpenLayers特征位置按地址搜索地址自动完成在地图上选择位置并点击从位置反向地址地理编码使用以下方法初始化位置选择器...
本套Java教程涵盖Ajax的实现原理,XMLHttpRequest实现Ajax,回调函数,Ajax数据交换格式(HTML、XML、JSON),Ajax...本视频教程循序渐进地对jQuery的各种选择器、函数和方法调用进行了详细的讲解,更结合了大量的案例。
从零开始学习jQuery (二) 万能的选择器 从零开始学习jQuery (三) 管理jQuery包装集 从零开始学习jQuery (四) 使用jQuery操作元素的属性与样式 从零开始学习jQuery (五) 事件与事件对象 从零开始学习jQuery (六) ...
课程目标什么是jQuery 是一个JavaScript的函数库 jQuery是一个轻量级的JavaScript库 浏览器兼容比较好 jQuery可以简化JavaScript代码适用人群...jQuery选择器的使用jQuery链式语法使用jQuery 代码优化设计jQuery动画
本文实例讲述了jquery+ajax实现省市区三级联动效果。分享给大家供大家参考,具体如下: 一直想学习下Ajax,没时间,汗,这借口太牵强了.下了点教程在手机里,翻了好几遍了,没实战一次. 最近的项目里需要Ajax实现效果,就...
QueryList使用jQuery选择器来做采集,让你告别复杂的正则表达式;QueryList具有jQuery一样的DOM操作能力、Http网络操作能力、乱码解决能力、内容过滤能力以及可扩展能力;可以轻松实现诸如:模拟登陆、伪造浏览器、...
5.4.4 理解jQuery选择 136 5.5 向页面添加内容 138 替换和删除选择 141 5.6 设置和读取标签属性 142 5.6.1 类 142 5.6.2 读取和改变CSS属性 143 5.6.3 一次改变多个CSS属性 145 5.7 读取、设置和删除HTML属性 146 ...
jQuery WeUI 是WeUI的一个jQuery实现版本,除了实现了官方插件之外,它还提供了如下拉刷新、日历、地址选择器等丰富的拓展组件。jQuery WeUI 中的JS组件均是以JQuery 插件的形式提供,使用非常方便,并且可以和React...
一,开篇分析 Hi,大家!今天这系列文章主要是说说如何开发基于“JavaScript”的插件式开发,我想很多人对”插件“这个词并不陌生...另一种是jQuery对象级别的方法,即挂在jQuery原型下的方法,这样通过选择器获取的jQu
PHP100视频教程107:JQuery 之选择器、事件器详解 PHP100视频教程108:JQuery之各类动画效果的实现 PHP100视频教程109:JQuery 之 Ajax 开发详解 PHP100视频教程110:Jquery案例 之 双下拉框内容移动 PHP100...
HTML基础加强、css(包含Div+CSS布局)、JavaScript、Dom(事件、window...JQuery函数、隐式迭代、链式编程、id选择器、tag选择器、CSS选择器、层次选择器、表单选择器、过滤选择器、复合选择器、节点导航、节点操作、...
关于一个选择器XML的小程序 C++控制台计算器(能识别括号) Java面试宝典 VC写的蝴蝶会动的时钟 清华大学C语言课件【超详细_很强大】 Struts,Hibernate,Spring集成开发宝典.pdf asp.net mvc教程 jquery-ui-1.9.2....
│ Java面试题39.jQuery中的常用选择器.mp4 │ Java面试题40.jQuery中页面加载完毕事件.mp4 │ Java面试题41.jQuery中Ajax和原生js实现Ajax的关系.mp4 │ Java面试题42.简单说一下html5.mp4 │ Java面试题43.简单说...
Gecco整合了jsoup、httpclient、fastjson、spring、htmlunit、redission等优秀框架,让您只需要配置一些jquery风格的选择器就能很快的写出一个爬虫。Gecco框架有优秀的可扩展性,框架基于开闭原则进行设计,对修改...
CyTOF数据可视化器 这是PCA和健壮的稀疏K均值(RSKM)的快速javascript实现。 实际上,这不一定是CyTOF数据,而是任何高维数据集。 请记住,一切都在浏览器中完成,因此选择一个大文件可能需要一些时间来进行分析。 ...
│ │ ├03 python s14 day 11 jQuery选择器eq和nth-child的区别_rec.mp4 │ │ ├04 python s14 day 11 jQuery表单选择器_rec.mp4 │ │ ├05 python s14 day 11 jQuery操作属性、css和返回顶部实例_rec.mp4 │ │ ...