jQuery使用(一):jQuery对象与选择器
一、简单的一些介绍
1.jQuery是由普通的是由一些系列操作DOM节点的函数和一些其他的工具方法组成的js库。
2.为什么要使用jQuery库?
jQuery面向用户良好的设计在使用过程中彻底解放了记忆原生操作DOM的接口。
jQuery中包含了可重用的函数,用来辅助我们简化JavaScript开发。
jQuery在半数以上并没有复杂交互的网站中得以大量使用,因为他们需要的仅仅是一些兼容低级浏览器又有炫酷效果动画的页面。
jQuery改变了数百万人编写JavaScript的方式,当然部分人已经觉得时过境迁,组件化,工程化大行其道,但不要忘记jQuery对前端开发者的启蒙意义!且很多公司项目依然需要使用。
3.jQuery注意点:
jQuery知识辅助工具,不能完全替代js,二者并存的方式出现在项目中;
jQuery很庞杂,先学使用再学思想。
jQuery方法很多,按需学习,把常用的学透彻。
jQuery API使用时可以现查现用,不难理解。
4.引入jQuery库:cdn:http://www.jq22.com/cdn/#a2
5.jQuery官网:中文:https://www.jquery123.com/英文原版:https://jQuery.com/
二、jQuery核心函数
在jQuery的应用开发中,我们经常看到这样的代码;
$("div .container").css("display","none"); //将div节点下样式值为container的节点设置为不显示 var width = $("div .container").width(); //得到div节点下样式值为container的宽度 var html = $(document.getElementById("result")).html(); //得到id为result的节点的innerHTML值 $("#result", document.forms[0]).css("color", "red"); //将在第一个Form节点下id为result的字体颜色设置为红色 $("<div>hello,world</div>").appendTo("#result"); //将HTML字符串信息 内部追加到 id为result的节点末尾
这里我们只关注jQuery的使用,不对源码进行分析,如需了解源码可以参考jQuery源码解析对象实例化与jQuery原型。
那么jQuer(...)里面的参数是什么?这个方法就可以实现什么呢?
<div class="a">...</div> <ul> <li>1</li> <li>2</li> </ul> <p id="b">...</p> <script> $(function(){ console.log($(".a"););//获取类名为a的元素(这里含元素div)的一个jQuery对象类数组 console.log($("ul li"););//获取ul元素下的li的所有元素构成的jQuery对象类数组 console.log($("#b"););//获取id为b的元素(这里是p元素)的jQuery对象。 }); </script>
$(...)的作用:
1.构建一个独立的jQuery代码块(作用域),参数一个function;
2.通过选择器构建jQuery元素节点对象和元素节点对象类数组。
3.还可以通过一个或多个DOM元素对象作为参数构建该元素的jQuery对象或对象类数组
$(...)的参数及容错机制:
当我们给$(...)传入null或者undefined,又或者传入的选择器字符串有误或者匹配不到元素的情况下,并不会报错,而是返回一个空的jQuery对象。
在构建独立的jQuery作用域时,浏览器对文件加载实现异步机制,jQuery再执行构建作用域前需要DOMContenLoaded(dom加载完毕)事件触发后再执行构建。所以为了保证jQuery代码顺利执行,jQuery会通过延迟机制触发window.onload事件,直到jQuery代码顺利执行。
三、jQuery选择器
(jQuery选择器的核心sizzle并不是并不是jQuery开发的,在这里为了让不是很了解内部源码的客官造成困扰,jQuery的选择器相较于css选择成为jQuery独有。)
1.jQuery常用选择器有ID选择器,类选择器,标签选择器,分组选择器,部分属性选择器,及父子选择器和并列选择器都基本与CSS选择器一致。这里对属性选择器做一些说明以外,其他选择器可以到我的另一篇博客了解学习总结:CSS(一)定义方式、选择器、选择器权重。
2.jQuery的属性选择器:jQuery的属性选择相对于css的属性选择器少了两个,下标四个选择器就是jQuery的属性选择器。
[attribute] | $("[href]") | 所有带有href属性的元素 |
[attribute=value] | $("href='#'") | 所有href属性的值等于"#"的元素 |
[attribute!=value] | $("href!='#'") | 所有href属性的值不等于"#" 的元素。 |
[attribute$=value] | $("href$='.jpg'") | 所有href属性的值包含以".jpg" 结尾的元素。 |
[attribute^=value] | $("htef^='atr'") | 所有href属性的值包含以"atr"开头的元素。 |
3.奇偶选择器与首尾选择器:这几种选择器是jQuery独有的选择器,这种奇偶首尾选择器是对jQuery对象类数组下标的一种操作。
:first | $("p:first") | 第一个<p>元素 |
:last | $("p:last") | 最后一个<p>元素 |
:even | $("tr:even") | 所有偶数<tr>元素 |
:odd | $("tr:odd") | 所有奇数<tr>元素 |
3.比较选择器与eq选择器:这几个选择器也同上面的一样,都是在匹配的基础上通过类数组的脚标来实现筛选。
:eq(index) | $("ul li:(3)") | 列表中的第四个元素(index从0开始) |
:gt(no) | $("ul li:gt(3)") | 列出index大于3的元素 |
:lt(no) | $("ul li:lt(3)") | 列出index小于3的元素 |
:not(selector) | $("input:not(:empty)") | 所有不为空的input元素(:empty表示无子(元素)节点的所有元素) |
这里就介绍这里比较常用的选择器,还有一些不常用的选择器如果需要了解可以访问W3C官方jQuery参考手册。
四、选择元素的方法
1.get()方法: get(index)--通过指定jQuery的DOM对象集合(类数组)的索引获取指定元素。索引值可以是下标(从0开始正向索引),也可以是负数(从-1开始反向索引)。不写参数的情况下就会返回整个jQuery的DOM对象集合的原生DOM集合(数组)。
<div class="demo">1</div> <div class="demo">2</div> <div class="demo">3</div> <div class="demo">4</div> <div class="demo">5</div> //js代码 console.log($('.demo').get(1));//<div class="demo">2</div> console.log($('.demo').get(-1));//<div class="demo">5</div> console.log($('.demo').get());//返回原生DOM集合(数组)
2.eq()方法:eq(index)--通过指定jQuery的DOM对象集合(类数组)的索引获取指定元素的jQuery对象,索引规则与get一致。
console.log($('.demo').eq(1));// console.log($('.demo').eq(-1));// console.log($('.demo').eq());//
这里上传一份仿写简版的jQuery代码,以供深入理解get和eq的原理:
/** * MyjQuery.js-1-2 * jQuery使用精髓 - 选择元素 - 循环操作 - 链式调用 * 实现--get方法 * 实现--eq方法 **/ (function(window,undefined){ //定义jQuery函数(接口方法) function jQuery(selector){ return new jQuery.prototype.init(selector); } //构建jQuery对象构造函数 jQuery.prototype.init = function(selector){ //选出dom 并且包装成jQuery对象 返回 // id css this.length = 0; //当获取的selector $()-$(null)--eq()-eq(null)这种情况时 if(selector == null){ return this; } if(typeof selector == 'string' && selector.indexOf('.') != -1){ var dom = document.getElementsByClassName(selector.slice(1)); }else if(typeof selector == 'string' && selector.indexOf('#') != -1){ var dom = document.getElementById(selector.slice(1)); } // if(selector instanceof Element){ // this[0] = selector; // } //将获取到的dom节点添加到jQuery对象上 if(selector instanceof Element || dom.length == undefined){ //--通过id获取到的dom只有一个节点没有length属性 this[0] = dom || selector; this.length++; }else{//--通过类获取到的dom节点集合本身就会有length属性 for(var i = 0; i < dom.length; i++){ this[i] = dom[i]; this.length++; } } } //给jQuery原型上添加工具方法 //--css操作方法 jQuery.prototype.css = function(config){ for(var i = 0; i < this.length; i++){ for(var attr in config){ this[i].style[attr] = config[attr]; } } //链式操作 return this; } //--get操作方法 jQuery.prototype.get = function(num){ // if(num == null){ // return [].slice.call(this,0); // }else{ // if(num >= 0){ // return this[num]; // }else{ // return this[num + this.length]; // } // } //三目运算符实现逻辑 return num != null ? (num >= 0 ? this[num] : this[num + this.length]) : [].slice.call(this,0); } //--eq操作方法 jQuery.prototype.eq = function(num){ var dom = num != null ? (num >= 0 ? this[num] : this[num + this.length]) : null; return jQuery(dom); } //将init原型(构造函数的原型)指向jQuery的原型 //实现了在jQuery原型定义工具方法,也是每个构造出来的实例对象的原型上的方法 jQuery.prototype.init.prototype = jQuery.prototype; //设置jQuery的接口 window.$ = window.jQuery = jQuery; })(window);
3.基于sezzleJS选择元素的方法:find、filter、not、has、is,sezzleJS是一个基于css选择器的js元素选择器脚本,是由第三方团队开发,并非jQuery团队开发的,很多开发js脚本都是基于sezzleJS的选择器来实现的,有意向开发自己的脚本库的小伙伴可以考虑深入研究这一块技术,这里我就不对sezzleJS做剖析,仅仅对这些方法做一些应用介绍。
find()方法:获取当前节点的所有后辈元素(子、孙、曾孙...),参数可以是元素选择器和jQuery对象。
<div class="wrapper"> <ul> <li>1</li> <li>2<span>span1</span></li> <li class="demo">3</li> <li>4<p><span>span2</span></p></li> <li class="demo">5</li> </ul> </div> //js代码 $('.wrapper').css({position:'relative'}) .find('ul').css({listStyle:'none'}) .find('li').css({color:'red'}); $('.wrapper').find('span').css({fontSize:'25px'});
find及很多dom节点遍历操作都是基于jQuery对象的prevObject属性来实现的,jQuery对象通过这个属性来保存当前的jQuery对象,是从哪个jQuery对象的DOM上下文获取的。
console.log($('.wrapper').prevObject);//document console.log($('.wrapper').find('ul').prevObject);//div console.log($('.wrapper').find('ul').find('li').prevObject);//ul
filter()方法:过滤函数--从指定的DOM节点集合中筛选出指定的DOM点。参数 css selector jquery--指向DOM集合中的部分DOM,jQuery选择器奇偶首尾选择器属于常用配合--first、last、even、odd。
console.log( $('.wrapper ul').find('li').filter('.demo') ); console.log( $('.wrapper ul').find('li:last') );//最后一个li
not()方法:的效果就是filter执行结果的反集
console.log( $('.wrapper ul').find('li').not(':even'));//除了下标为偶数的li,包括0
has()方法:has方法与filter方法非常类似,filter通过DOM节点的自身的类或特性来筛选,has通过识别节点拥有某些子节点来筛选自己(参数为选择器或者元素节点)。
console.log($('.wrapper ul').find('li').has('span,p'));//筛选到含有子节点span和p元素的li
is()方法:用来检测一个jQuery对象中的DOM(集合)是否含有某个指定的元素,如果有就返回true。
console.log( $('.wrapper ul').find('li').is('.demo') );
//li的jQuey对象元素集合中有li元素包含有class为demo的li,返回true
4.jQuery链式调用(串联):合并、回退与pushStack
add()方法:将新匹配到的元素节点集与当前元素节点集合并,参数可以是任何jQuery选择器,在产生DOM节点重复合并时,合并的结果里不会出现重复的节点。
console.log($('div').add('.wrapper'));
console.log($('.demo').add('.wrapper'));
end()方法:回退到当前jQuery对象的上一个jQuery对象,也就是产生当前jQuery对象的父对象。如果当前jQuery对象是最初的对象,则返回当前文档document的jQuery对象。
console.log($('.wrapper').end());//document console.log($('.wrapper').find('li').end());//wrapper
end方法有一次基于jQuery的prevObject属性来实现了,其实前面在find部分介绍prevObject属性并不完全合适,在那个阶段至add都是写入prevObject的属性值,真正应用这个值的时候是end方法。这里我们可以模仿jQuery源码来实现自己MyjQuery的链式调用功能。(注意add仿写功能并没有对重复节点进行处理)
(function(window,undefined){ //定义jQuery函数(接口方法) function jQuery(selector){ return new jQuery.prototype.init(selector); } //构建jQuery对象构造函数 jQuery.prototype.init = function(selector){ //选出dom 并且包装成jQuery对象 返回 // id css this.length = 0; this.prevObject = document; //当获取的selector $()-$(null)--eq()-eq(null)这种情况时 if(selector == null){ return this; } if(typeof selector == 'string' && selector.indexOf('.') != -1){ var dom = document.getElementsByClassName(selector.slice(1)); }else if(typeof selector == 'string' && selector.indexOf('#') != -1){ var dom = document.getElementById(selector.slice(1)); } // if(selector instanceof Element){ // this[0] = selector; // } //将获取到的dom节点添加到jQuery对象上 if(selector instanceof Element || dom.length == undefined){ //--通过id获取到的dom只有一个节点没有length属性 this[0] = dom || selector; this.length++; }else{//--通过类获取到的dom节点集合本身就会有length属性 for(var i = 0; i < dom.length; i++){ this[i] = dom[i]; this.length++; } } } //给jQuery原型上添加工具方法 //--css操作方法 jQuery.prototype.css = function(config){ for(var i = 0; i < this.length; i++){ for(var attr in config){ this[i].style[attr] = config[attr]; } } //链式操作 return this; } jQuery.prototype.pushStack = function(dom){ if( !dom || dom.constructor != jQuery){ dom = jQuery(dom); } dom.prevObject = this; return dom; } //--get操作方法 jQuery.prototype.get = function(num){ // if(num == null){ // return [].slice.call(this,0); // }else{ // if(num >= 0){ // return this[num]; // }else{ // return this[num + this.length]; // } // } //三目运算符实现逻辑 return num != null ? (num >= 0 ? this[num] : this[num + this.length]) : [].slice.call(this,0); } //--eq操作方法 jQuery.prototype.eq = function(num){ var dom = num != null ? (num >= 0 ? this[num] : this[num + this.length]) : null; return this.pushStack(dom); } //--add合并操作 jQuery.prototype.add = function(selector){ var curObj = jQuery(selector); var baseObj = this; var newObje = jQuery(); for(var i = 0; i < curObj.length; i++){ newObje[newObje.length++] = curObj[i]; } for(var i = 0; i < baseObj.length; i++){ newObje[newObje.length++] = baseObj[i]; } //newObje.prevObject = this; this.pushStack(newObje); return newObje; } //--end回退功能 jQuery.prototype.end = function(){ return this.prevObject; } //将init原型(构造函数的原型)指向jQuery的原型 //实现了在jQuery原型定义工具方法,也是每个构造出来的实例对象的原型上的方法 jQuery.prototype.init.prototype = jQuery.prototype; //设置jQuery的接口 window.$ = window.jQuery = jQuery; })(window);
这部分源码重点用来来说明jQuery的链式调用原理,涉及节点获取链式指向prevObject和样式方法的放回this,其中jQuery中的end方法和pushStack值得我们借鉴。
最后还有一个节点获取方法slice()用来获取当前节点的子节点,这个方法和find是有区别的,find()是用来获取全部后代元素节点,slice()只是用来获取子节点而已。