多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
jQuery is just a **JavaScript library**. [[官方学习中心]](https://learn.jquery.com/about-jquery/) ---- [TOC] ---- ## 0. code organization website: [http://learn.jquery.com/code-organization/concepts/](http://learn.jquery.com/code-organization/concepts/) some concepts that are common to all good code organization patterns. >* Your code should be divided into units of functionality — modules, services, etc. Avoid the temptation to have all of your code in one huge $( document ).ready() block. This concept, loosely, is known as encapsulation. >* Don't repeat yourself. Identify similarities among pieces of functionality, and use inheritance techniques to avoid repetitive code. >* Despite jQuery's DOM-centric nature, JavaScript applications are not all about the DOM. Remember that not all pieces of functionality need to — or should — have a DOM representation. >* Units of functionality should be loosely coupled, that is, a unit of functionality should be able to exist on its own, and communication between units should be handled via a messaging system such as custom events or pub/sub. Stay away from direct communication between units of functionality whenever possible. ### 0.1 code organization patterns #### 0.1.1 traditional jQuery style ~~~ javascript // Clicking on a list item loads some content using the // list item's ID, and hides content in sibling list items $( document ).ready(function() { $( "#myFeature li" ).append( "<div>" ).click(function() { var item = $( this ); var div = item.find( "div" ); div.load( "foo.php?item=" + item.attr( "id" ), function() { div.show(); item.siblings().find( "div" ).hide(); }); }); }); ~~~ #### 0.1.2 object literal style ~~~ javascript // Using an object literal for a jQuery feature var myFeature = { init: function( settings ) { myFeature.config = { items: $( "#myFeature li" ), container: $( "<div class='container'></div>" ), urlBase: "/foo.php?item=" }; // Allow overriding the default config $.extend( myFeature.config, settings ); myFeature.setup(); }, setup: function() { myFeature.config.items .each( myFeature.createContainer ) .click( myFeature.showItem ); }, createContainer: function() { var item = $( this ); var container = myFeature.config.container .clone() .appendTo( item ); item.data( "container", container ); }, buildUrl: function() { return myFeature.config.urlBase + myFeature.currentItem.attr( "id" ); }, showItem: function() { myFeature.currentItem = $( this ); myFeature.getContent( myFeature.showContent ); }, getContent: function( callback ) { var url = myFeature.buildUrl(); myFeature.currentItem.data( "container" ).load( url, callback ); }, showContent: function() { myFeature.currentItem.data( "container" ).show(); myFeature.hideContent(); }, hideContent: function() { myFeature.currentItem.siblings().each(function() { $( this ).data( "container" ).hide(); }); } }; $( document ).ready( myFeature.init ); ~~~ benifit: * We've broken our feature up into tiny methods. In the future, if we want to change how content is shown, it's clear where to change it. In the original code, this step is much harder to locate. * We've eliminated the use of anonymous functions. * We've moved configuration options out of the body of the code and put them in a central location. * We've eliminated the constraints of the chain, making the code easier to refactor, remix, and rearrange. For non-trivial features, object literals are a clear improvement over a long stretch of code stuffed in a `$( document ).ready()` block, as they get us thinking about the pieces of our functionality. However, they aren't a whole lot more advanced than simply having a bunch of function declarations inside of that `$( document ).ready()` block. #### 0.1.3 The Module Pattern style The module pattern overcomes some of the limitations of the object literal, offering privacy for variables and functions while exposing a public API if desired. ~~~javascript // The module pattern var feature = (function() { // Private variables and functions var privateThing = "secret"; var publicThing = "not secret"; var changePrivateThing = function() { privateThing = "super secret"; }; var sayPrivateThing = function() { console.log( privateThing ); changePrivateThing(); }; // Public API return { publicThing: publicThing, sayPrivateThing: sayPrivateThing }; })(); feature.publicThing; // "not secret" // Logs "secret" and changes the value of privateThing feature.sayPrivateThing(); ~~~ In the example above, we self-execute an anonymous function that returns an object. This pattern is powerful because, as you can gather from the variable names, it can give you private variables and functions while exposing a limited API consisting of the returned object's properties and methods. Below is a revised version of the previous example, showing how we could create the same feature using the module pattern while only exposing one public method of the module, `showItemByIndex()`. ~~~Javascript // Using the module pattern for a jQuery feature $( document ).ready(function() { var feature = (function() { var items = $( "#myFeature li" ); var container = $( "<div class='container'></div>" ); var currentItem = null; var urlBase = "/foo.php?item="; var createContainer = function() { var item = $( this ); var _container = container.clone().appendTo( item ); item.data( "container", _container ); }; var buildUrl = function() { return urlBase + currentItem.attr( "id" ); }; var showItem = function() { currentItem = $( this ); getContent( showContent ); }; var showItemByIndex = function( idx ) { $.proxy( showItem, items.get( idx ) ); }; var getContent = function( callback ) { currentItem.data( "container" ).load( buildUrl(), callback ); }; var showContent = function() { currentItem.data( "container" ).show(); hideContent(); }; var hideContent = function() { currentItem.siblings().each(function() { $( this ).data( "container" ).hide(); }); }; items.each( createContainer ).click( showItem ); return { showItemByIndex: showItemByIndex }; })(); feature.showItemByIndex( 0 ); }); ~~~ ### 0.2 Beware Anonymous Functions Anonymous functions bound everywhere are a pain. They're difficult to debug, maintain, test, or reuse. Instead, use an object literal to organize and name your handlers and callbacks. ~~~JavaScript // BAD $( document ).ready(function() { $( "#magic" ).click(function( event ) { $( "#yayeffects" ).slideUp(function() { // ... }); }); $( "#happiness" ).load( url + " #unicorns", function() { // ... }); }); // BETTER var PI = { onReady: function() { $( "#magic" ).click( PI.candyMtn ); $( "#happiness" ).load( PI.url + " #unicorns", PI.unicornCb ); }, candyMtn: function( event ) { $( "#yayeffects" ).slideUp( PI.slideCb ); }, slideCb: function() { ... }, unicornCb: function() { ... } }; $( document ).ready( PI.onReady ); ~~~ ### 0.3 Keep Things DRY Don't repeat yourself; if you're repeating yourself, you're doing it wrong. ~~~JavaScript // BAD if ( eventfade.data( "currently" ) !== "showing" ) { eventfade.stop(); } if ( eventhover.data( "currently" ) !== "showing" ) { eventhover.stop(); } if ( spans.data( "currently" ) !== "showing" ) { spans.stop(); } // GOOD!! var elems = [ eventfade, eventhover, spans ]; $.each( elems, function( i, elem ) { if ( elem.data( "currently" ) !== "showing" ) { elem.stop(); } }); ~~~ ### 0.4 Feature Detection Tools: * [modernizr](https://modernizr.com/docs/) — Conditionally check to see if a specific feature is available in a browser. * [html5please](http://html5please.com/) — Use the new and shiny responsibly. * html5please API — An API you can query to see how good (or bad) support for a specific feature is. * [caniuse](https://caniuse.com/) — Browser compatibility tables for HTML5, CSS3, SVG, etc. Articles: * [Browser Feature Detection](https://developer.mozilla.org/en-US/docs/Archive/Web/Browser_feature_detection) * [Using Modernizr to detect HTML5 and CSS3 browser support](https://www.adobe.com/devnet/archive/dreamweaver/articles/using-modernizr.html) * [Polyfilling the HTML5 gaps](https://addyosmani.com/polyfillthehtml5gaps/slides/#1) by Addy Osmani * [Feature, Browser, and Form Factor Detection: It's Good for the Environment](https://www.html5rocks.com/en/tutorials/detection/index.html) by Michael Mahemoff ## 1 .选择器 ## 2. 链式方法 ## 3. 类型(Types) [(https://api.jquery.com/Types/)](https://api.jquery.com/Types/) ### 3.1 函数(function) 函数可以赋值给变量,也可以传递给方法。但传递给方法的成员函数有可能会因为名字相同而引用成其他对象的成员函数。 #### 3.1.1 命名 - 匿名(anonymous) ~~~javascript $( document ).ready(function() { $( "a" ).click(function() {}); $.ajax({ url: "someurl.php", success: function() {} }); }); ~~~ - 命名(named) ~~~javascript function named() {} var handler = function() {} ~~~ #### 3.1.2 参数(arguments) ~~~javascript function log( x ) { console.log( typeof x, arguments.length ); } log(); // "undefined", 0 log( 1 ); // "number", 1 log( "1", "2", "3" ); // "string", 3 ~~~ 如上述代码所示,在函数体中特殊变量``arguments``总是可用的,它有一个类似数组长度的属性``length``,可以用来得到函数参数的个数。另外还有一个``callee``属性,指出所在函数名,如下: ~~~javascript var awesome = function() { return arguments.callee; } awesome() === awesome // true ~~~ #### 3.1.3 上下文、调用、应用(context、call、apply) 在JavaScript中,变量``this``总是指代当前所在的上下文环境。 默认情况下,``this``指代window对象。但在函数中,要根据函数的调用形式来确定``this``指代的上下文环境。 在jQuery中,所有的事件处理函数(event handler)通过处理元素(handling element)作为上下文来调用。例如: ~~~javascript $( document ).ready(function() { // this refers to window.document $(this).close; }); $( "a" ).click(function() { // this refers to an anchor DOM element $(this).hide(); }); ~~~ 还可以通过函数内置(function-built-in)的方法``call``或者``apply``指定函数调用的上下文。 ``call``:将所有的参数作为一个``arguments``传给所调用的函数。 ``apply``:将所有的参数作为数组传给所调用的函数。 ~~~javascript function scope() { console.log( this, arguments.length ); } scope() // window, 0 scope.call( "foobar", [ 1, 2 ] ); // "foobar", 1 scope.apply( "foobar", [ 1, 2 ] ); // "foobar", 2 ~~~ #### 3.1.4 变量范围(scope) 在JavaScript中,在函数体内定义的变量仅在函数体内可见、有效。 ~~~javascript // global var x = 0; (function() { // private var x = 1; console.log( x ); // 1 })(); console.log( x ); // 0 ~~~ 如上述代码所示,函数体内的变量x与全局变量x相互独立,互不影响。 #### 3.1.5 闭包(closures) ~~~javascript function create() { var counter = 0; return { increment: function() { counter++; }, print: function() { console.log( counter ); } } } var c = create(); c.increment(); c.print(); // 1 ~~~ 如上述代码所示,变量``counter``仅在函数create,increment,print中可见。这一模式源自面向对象编程(OOP,Object-Oriented Programming)的基本原则:可以使用对象的方法来操作对象外部不可见的对象内部数据。 #### 3.1.6 代理模式(proxy pattern) 结合上述的特性JavaScript的开发者可以有更多的灵活性。jQuery插件的实现方式。 比如,在JavaScript可以实现代理模式(proxy pattern)——面向方面编程(AOP,Aspect-Oriented Programming)的基础: ~~~javascript (function() { // log all calls to setArray var proxied = jQuery.fn.setArray; jQuery.fn.setArray = function() { console.log( this, arguments ); return proxied.apply( this, arguments ); }; })(); ~~~ 如上述代码所示,一个闭包函数封装了``proxied``变量。该函数封装并重写了jQuery的``setArray``方法。然后,代理将所有对该方法的调用导向该闭包函数。 使用``apply``的方法能保证函数的调用者不会感知原有的方法和新的方法间的区别。 ### 3.2 回调(callback) 回调就是一个普通的JavaScript函数,是作为参数或可选项传递给某些方法的。某些回调就是作为事件,方便用户在某种状态被触发后可进行一些操作的。 jQuery的事件系统(event system)使用了大量的回调,类似: ~~~javascript $( "body" ).click(function( event ) { console.log( "clicked: " + event.target ); }); ~~~ 如上例,回调是通过一个参数也是事件(Event)``event``调用的,上下文(context)设定为发生事件的元素``document.body``。 回调也可以有返回值。为了避免表单的提交,一个提交事件处理函数(submit event handler)应该返回false: ~~~javascript $( "#myform" ).submit(function() { return false; }); ~~~ 更好的做法是该回调处理函数检查表单域的有效性,在表单无效时返回false。 ### $.deferred() The callbacks attached to done() will be fired when the deferred is resolved. The callbacks attached to fail() will be fired when the deferred is rejected. ### $.ajax() success() and error() are only available on the jqXHR object returned by a call to ajax(). They are simple aliases for done() and fail() respectively: jqXHR.done === jqXHR.success jqXHR.fail === jqXHR.error ## 4. jQuery插件开发 [http://www.cnblogs.com/Wayou/p/jquery_plugin_tutorial.html](http://www.cnblogs.com/Wayou/p/jquery_plugin_tutorial.html) 根据《jQuery高级编程》的描述,jQuery插件开发方式主要有三种: * 通过$.extend()来扩展jQuery * 通过$.fn 向jQuery添加新的方法 * 通过$.widget()应用jQuery UI的部件工厂方式创建 通常我们使用第二种方法来进行简单插件开发,说简单是相对于第三种方式。第三种方式是用来开发更高级jQuery部件的,该模式开发出来的部件带有很多jQuery内建的特性,比如插件的状态信息自动保存,各种关于插件的常用方法等,非常贴心,这里不细说。 ### 4.1 通过$.extend()来扩展jQuery 这种方式用来定义一些辅助方法是比较方便的。比如一个自定义的console,输出特定格式的信息,定义一次后可以通过jQuery在程序中任何需要的地方调用它。 ~~~javascript $.extend({ log: function(message) { var now = new Date(), y = now.getFullYear(), m = now.getMonth() + 1, //!JavaScript中月分是从0开始的 d = now.getDate(), h = now.getHours(), min = now.getMinutes(), s = now.getSeconds(), time = y + '/' + m + '/' + d + ' ' + h + ':' + min + ':' + s; console.log(time + ' My App: ' + message); } }) $.log('initializing...'); //调用 ~~~ 但这种方式无法利用jQuery强大的选择器带来的便利,要处理DOM元素以及将插件更好地运用于所选择的元素身上,还是需要使用第二种开发方式。你所见到或使用的插件也大多是通过此种方式开发。 ### 4.2 通过$.fn 向jQuery添加新的方法 > ### 基本方法 先看一下它的基本格式: ~~~javascript $.fn.pluginName = function() { //your code goes here } ~~~ 例如: ~~~javascript $.fn.myPlugin = function() { //在这里面,this指的是用jQuery选中的元素 //example :$('a'),则this=$('a') this.css('color', 'red'); } ~~~ 在插件名字定义的这个函数内部,`this`指代的是我们在调用该插件时,用jQuery选择器选中的元素,一般是一个jQuery类型的`集合`。 比如$('a')返回的是页面上所有a标签的集合,且这个集合已经是jQuery包装类型了,也就是说,在对其进行操作的时候可以直接调用jQuery的其他方法而不需要再用$来包装一下。 所以在上面插件代码中,我们在`this`身上调用jQuery的css()方法,也就相当于在调用` $('a').css()`。 接下来,在插件代码里处理每个具体的元素,而不是对一个集合进行处理,这样我们就可以针对每个元素进行相应操作。 例如: ~~~javascript $.fn.myPlugin = function() { //在这里面,this指的是用jQuery选中的元素 this.css('color', 'red'); this.each(function() { //对每个元素进行操作 $(this).append(' ' + $(this).attr('href')); })) } ~~~ 如前所述,`this`指代jQuery选择器返回的`集合`,那么通过调用jQuery的`.each()`方法就可以处理合集中的每个元素了,但此刻要注意的是,在each方法内部,this指带的是普通的DOM元素了,如果需要调用jQuery的方法那就需要用$来重新包装一下。 如上述代码中,每个链接显示链接的真实地址,首先通过each遍历所有a标签,然后获取href属性的值再加到链接文本后面。 > ### 支持链式调用 我们都知道jQuery一个时常优雅的特性是支持链式调用,选择好DOM元素后可以不断地调用其他方法。 要让插件不打破这种链式调用,只需return一下即可。 ~~~javascript $.fn.myPlugin = function() { //在这里面,this指的是用jQuery选中的元素 this.css('color', 'red'); return this.each(function() { //对每个元素进行操作 $(this).append(' ' + $(this).attr('href')); })) } ~~~ > ### 让插件接收参数 在处理插件参数的接收上,通常使用jQuery的`$.extend()`方法,当给extend方法传递一个以上的参数时,它会将所有参数对象合并到第一个里。同时,如果对象中有同名属性时,合并的时候后面的会覆盖前面的。 利用这一点,我们可以在插件里定义一个保存插件参数默认值的对象,同时将接收来的参数对象合并到默认对象上,最后就实现了用户指定了值的参数使用指定的值,未指定的参数使用插件默认值。 一个好的做法是将一个新的空对象做为$.extend的第一个参数,defaults和用户传递的参数对象紧随其后,这样做的好处是所有值被合并到这个空对象上,保护了插件里面的默认值。 ~~~javascript $.fn.myPlugin = function(options) { var defaults = { 'color': 'red', 'fontSize': '12px' }; var settings = $.extend({},defaults, options);//将一个空对象做为第一个参数 return this.css({ 'color': settings.color, 'fontSize': settings.fontSize }); } ~~~ > ### 面向对象的插件开发 要编写一个复杂的插件,代码量会很大,如何组织代码就成了一个需要面临的问题,没有一个好的方式来组织这些代码,整体感觉会杂乱无章,同时也不好维护,所以将插件的所有方法属性包装到一个对象上,用面向对象的思维来进行开发,无疑会使工作轻松很多。 如果将需要的重要变量定义到对象的属性上,函数变成对象的方法,当我们需要的时候通过对象来获取,一来方便管理,二来不会影响外部命名空间,因为所有这些变量名还有方法名都是在对象内部。 ~~~javascript //定义Beautifier的构造函数 var Beautifier = function(ele, opt) { this.$element = ele, this.defaults = { 'color': 'red', 'fontSize': '12px', 'textDecoration':'none' }, this.options = $.extend({}, this.defaults, opt) } //定义Beautifier的方法 Beautifier.prototype = { beautify: function() { return this.$element.css({ 'color': this.options.color, 'fontSize': this.options.fontSize, 'textDecoration': this.options.textDecoration }); } } //在插件中使用Beautifier对象 $.fn.myPlugin = function(options) { //创建Beautifier的实体 var beautifier = new Beautifier(this, options); //调用其方法 return beautifier.beautify(); } ~~~ 以后要加新功能新方法,只需向对象添加新变量及方法即可,然后在插件里实例化后即可调用新添加的东西。 插件的调用还是一样的,对代码的改动并不影响插件其他地方,只是将代码的组织结构改动了而以。 ~~~javascript $(function() { $('a').myPlugin({ 'color': '#2C9929', 'fontSize': '20px' }); }) ~~~ > ### 关于命名空间 不仅仅是jQuery插件的开发,我们在写任何JS代码时都应该注意的一点是不要污染全局命名空间。因为随着你代码的增多,如果有意无意在全局范围内定义一些变量的话,最后很难维护,也容易跟别人写的代码有冲突。 比如你在代码中向全局window对象添加了一个变量status用于存放状态,同时页面中引用了另一个别人写的库,也向全局添加了这样一个同名变量,最后的结果肯定不是你想要的。所以不到万不得已,一般我们不会将变量定义成全局的。 一个好的做法是始终用`自调用匿名函数`(javascript-self-invoking-functions)包裹你的代码,这样就可以完全放心,安全地将它用于任何地方了,绝对没有冲突。 如上面我们定义了一个Beautifier全局变量,它会被附到全局的window对象上,为了防止这种事情发生,你或许会说,把所有代码放到jQuery的插件定义代码里面去啊,也就是放到$.fn.myPlugin里面。这样做倒也是种选择。但会让我们实际跟插件定义有关的代码变得臃肿,而在$.fn.myPlugin里面我们其实应该更专注于插件的调用,以及如何与jQuery互动。 所以保持原来的代码不变,我们将所有代码用自调用匿名函数包裹: ~~~javascript (function() { //定义Beautifier的构造函数 var Beautifier = function(ele, opt) { this.$element = ele, this.defaults = { 'color': 'red', 'fontSize': '12px', 'textDecoration': 'none' }, this.options = $.extend({}, this.defaults, opt) } //定义Beautifier的方法 Beautifier.prototype = { beautify: function() { return this.$element.css({ 'color': this.options.color, 'fontSize': this.options.fontSize, 'textDecoration': this.options.textDecoration }); } } //在插件中使用Beautifier对象 $.fn.myPlugin = function(options) { //创建Beautifier的实体 var beautifier = new Beautifier(this, options); //调用其方法 return beautifier.beautify(); } })(); ~~~ 我们知道JavaScript中无法用花括号方便地创建作用域,但函数却可以形成一个作用域,域内的代码是无法被外界访问的。如上所示,用自调用匿名函数包裹代码后的好处有: * 我们将自己的代码放入一个函数中,就不会污染全局命名空间,同时不会和别的代码冲突。 * 自调用匿名函数里面的代码会在第一时间执行,页面准备好后,上面的代码就将插件准备好了,以方便在后面的代码中使用插件。 >### 将系统变量以变量形式传递到插件内部 ~~~javascript var foo=function(){ //别人的代码 }//注意这里没有用分号结尾 //开始我们的代码。。。 (function(){ //我们的代码。。 alert('Hello!'); })(); ~~~ 本来别人的代码也正常工作,只是最后定义的那个函数没有用分号结尾而以,然后当页面中引入我们的插件时,报错了,我们的代码无法正常执行。原因是我们用来充当自调用匿名函数的第一对括号与上面别人定义的函数相连,因为中间没有分号嘛,总之我们的代码无法正常解析了,所以报错。 所以好的做法是我们在代码开头加一个分号,这在任何时候都是一个好的习惯。同时,将系统变量以参数形式传递到插件内部也是个不错的实践。 当我们这样做之后,`window`等系统变量在插件内部就有了一个局部的引用,可以提高访问速度,会有些许性能的提升,最后我们得到一个非常安全结构良好的代码: ~~~javascript ;(function($,window,document,undefined){ //我们的代码。。 //blah blah blah... })(jQuery,window,document); ~~~ 而至于这个undefined,稍微有意思一点,为了得到没有被修改的undefined,我们并没有传递这个参数,但却在接收时接收了它,因为实际并没有传,所以‘undefined’那个位置接收到的就是真实的'undefined'了。 `undefined` is simply used for readability to indicating that no more arguments are passed to the function. >### 代码混淆与压缩 下载的插件里面,一般都会提供一个压缩的版本一般在文件名里带个'min'字样。也就是minified的意思,压缩浓缩后的版本。并且平时我们使用的jQuery也是官网提供的压缩版本,jquery.min.js。 这里的压缩不是指代码进行功能上的压缩,而是通过将代码里面的变量名,方法函数名等等用更短的名称来替换,并且删除注释(如果有的话)删除代码间的空白及换行所得到的浓缩版本。同时由于代码里面的各种名称都已经被替代,别人无法阅读和分清其逻辑,也起到了混淆代码的作用。 压缩的好处: * 源码经过混淆压缩后,体积大大减小,使代码变得轻量级,同时加快了下载速度,两面加载变快。比如正常jQuery v1.11.0的源码是276kb,而压缩后的版本仅94.1kb!体积减小一半还多。这个体积的减小对于文件下载速度的提升不可小觑。 * 经过压缩混淆后,代码还能阅读嘛?当然不能,所以顺带还起到了代码保护的作用。当然只是针对你编写了一些比较酷的代码又不想别人抄袭的情况。对于jQuery社区,这里本身就是开源的世界,同时JavaScript这东西其实也没什么实质性方法可以防止别人查看阅读你的代码,毕竟有混淆就有反混淆工具,这里代码压缩更多的还是上面提到的压缩文件的作用,同时一定程度上防止别人抄袭。 工具 所使用的工具推崇的是Google开发的Closure Compiler。该工具需要Java环境的支持,所以使用前你可能需要先在机子上装JRE, 然后再获取Closure进行使用。 同时也有很朋在线的代码混淆压缩工具,用起来也很方便。这些工具都是一搜一大把的。 ## 5. 操作DOM元素 ### 5.1 操作`<select>` 参考1:[https://blog.csdn.net/qq_16055765/article/details/54173553](https://blog.csdn.net/qq_16055765/article/details/54173553) 参考2:[https://blog.csdn.net/nairuohe/article/details/6307367](https://blog.csdn.net/nairuohe/article/details/6307367) jQuery操作“select”, 说的更确切一些是应该是jQuery控制 “option” HTML: ~~~html <select id="test"> <option value="1">选项一<option> <option value="2">选项一<option> ... <option value="n">选项N<option> </select> ~~~ * 获取option的值 ~~~javascript //第一个option $('#test option:first').val(); //最后一个option $('#test option:last').val(); //第二个option $('#test option:eq(1)').val(); //选中的option $('#test').val(); $('#test option:selected').val(); $('#test').find('option:selected').val(); $('#test').children('option:selected').val() ~~~ * 获取option的text ~~~javascript //获取选中option $('#test').find('option:selected').text(); ~~~ >[info]这里用到了冒号,掌握它的用法并举一反三也会让代码变得简洁。 * 设置option为选中状态 ~~~javascript //设置值为2的option $('#test').attr('value','2'); $('#test').val('2'); //设置text为pxx的项选中 $('#test').find('option[text="pxx"]').attr('selected',true); $('#test option').each(function(){ if($(this).text()=='pxx'){ $(this).attr('selected',true); } }); //设置最后一个option $('#test option:last').attr('selected','selected'); $('#test').find('option:last').attr('selected',true); $('#test').attr('value' , $('#test option:last').val()); $('#test').attr('value' , $('#test option').eq($('#test option').length - 1).val()); //默认选中 $('#test').find('option[value="'+xxvalue+'"]').prop('selected',true); ~~~ >[info] 这里有一个中括号的用法,中括号里的等号的前面是属性名称,不用加引号。很多时候,中括号的运用可以使得逻辑变得很简单。 * 获取select的长度 ~~~javascript $('#test option').length; ~~~ * 添加一个option ~~~javascript $("#test").append("<option value='n+1'>第N+1项</option>"); $("<option value='n+1'>第N+1项</option>").appendTo("#test"); ~~~ * 移除option ~~~javascript //删除选中项 $('#test option:selected').remove(); //删除第一项 $('#test option:first').remove();、 //指定项被删除 $('#test option').each(function(){ if( $(this).val() == '5'){ $(this).remove(); } }); $('#test option[value=5]').remove(); ~~~ * 其他 ~~~javascript //获取第一个Group的标签 $('#test optgroup:eq(0)').attr('label'); //获取第二group下面第一个option的值 $('#test optgroup:eq(1) : option:eq(0)').val(); ~~~ * select的级联,即第二个select的值随着第一个select选中的值变化。 ~~~javascript $(".selector1").change(function(){ // 先清空第二个 $(".selector2").empty(); // 实际的应用中,这里的option一般都是用循环生成多个了 var option = $("<option>").val(1).text("pxx"); $(".selector2").append(option); }); ~~~ ### 5.2 操作`<radio>` $.val(),对`value`属性进行取值 $.val(‘xx’),对`value`属性进行赋值 $.prop('checked'),对`checked`属性进行取值 $.prop('checked',false),对`checked`属性进行赋值 ### 5.3 操作`<checkbox>` $.val(),对`value`属性进行取值 $.val(‘xx’),对`value`属性进行赋值 $.prop('checked'),对`checked`属性进行取值 $.prop('checked',false),对`checked`属性进行赋值 ## 6. jQuery API jQuery API [3.3.1速查表](http://jquery.cuishifeng.cn) ### 6.1 核心 #### 6.1.1 jQuery 对象访问 * each(callback) * length * selector * context * get(\[index]) * index(\[selector\[element]) #### 6.1.2 数据缓存 * data(\[key],\[value]) * removeData(\[name|list]]) #### 6.1.3 插件机制 * jQuery.fn.extend(object) * jQuery.extend(object) #### 6.1.4 队列控制 * queue(e,\[q]) * dequeue(\[queueName]) * clearQueue(\[queueName]) ## X Deferred Object (延迟)对象,回调函数处理队列,jQuery.Deferred(),实现JavaScript的promise模式?? **Deferreds** [link](http://learn.jquery.com/code-organization/deferreds/) At a high-level, deferreds can be thought of as a way to represent asynchronous operations which can take a long time to complete. They're the asynchronous alternative to blocking functions and the general idea is that rather than your application blocking while it awaits some request to complete before returning a result, a deferred object can instead be returned immediately. You can then attach callbacks to the deferred object: they will be called once the request has actually completed. **Promises** In its most basic form, a "promise" is a model that provides a solution for the concept of deferred (or future) results in software engineering. The main idea behind it is something we've already covered: rather than executing a call which may result in blocking, we instead return a promise for a future value that will eventually be satisfied. The pseudo-code for dealing with a third party API that returns a promise may look like: ~~~JavaScript var promise = callToAPI( arg1, arg2, ...); promise.then(function( futureValue ) { // Handle futureValue }); promise.then(function( futureValue ) { // Do something else }); ~~~ Furthermore, a promise can actually end up being in two different states: * Resolved: in which case data is available * Rejected: in which case something went wrong and no value is available the "then" method accepts two parameters: one for when the promise was resolved, another for when the promise was rejected. If we get back to pseudo-code, we may do things like: ~~~JavaScript promise.then(function( futureValue ) { // We got a value }, function() { // Something went wrong }); ~~~ In the case of certain applications, it is necessary to have several results returned before your application can continue at all (for example, displaying a dynamic set of options on a screen before a user is able to select the option that interests them). Where this is the case, a method called "when" exists, which can be used to perform some action once all the promises have been fully fulfilled: ~~~JavaScript when( promise1, promise2, ... ).then(function( futureValue1, futureValue2, ... ) { // All promises have completed and are resolved }); ~~~ A good example is a scenario where you may have multiple concurrent animations that are being run. Without keeping track of each callback firing on completion, it can be difficult to truly establish once all your animations have finished running. Using promises and "when" however this is very straightforward as each of your animations can effectively say "we promise to let you know once we're done". The compounded result of this means it's a trivial process to execute a single callback once the animations are done. For example: ~~~JavaScript var promise1 = $( "#id1" ).animate().promise(); var promise2 = $( "#id2" ).animate().promise(); when( promise1, promise2 ).then(function() { // Once both animations have completed // we can then run our additional logic }); ~~~ This means that one can basically write non-blocking logic that can be executed without synchronization. Rather than directly passing callbacks to functions, something which can lead to tightly coupled interfaces, using promises allows one to separate concerns for code that is synchronous or asynchronous. **jQuery Deferreds** [link](http://learn.jquery.com/code-organization/deferreds/jquery-deferreds/#jquery-deferreds) At the heart of jQuery's implementation is `jQuery.Deferred` — a chainable constructor which is able to create new deferred objects that can check for the existence of a promise to establish whether the object can be observed. It can also invoke callback queues and pass on the success of synchronous and asynchronous functions. It's quite essential to note that the default state of any Deferred object is unresolved. Callbacks which may be added to it through` .then()` or `.fail()` are queued up and get executed later on in the process. You are able to use Deferred objects in conjunction with the promise concept of when(), implemented in jQuery as $.when() to wait for all of the Deferred object's requests to complete executing (i.e. for all of the promises to be fulfilled). In technical terms, `$.when() `is effectively a way to execute callbacks based on any number of promises that represent asynchronous events. An example of `$.when()` accepting multiple arguments can be seen below in conjunction with `.then()`: ~~~JavaScript function successFunc() { console.log( "success!" ); } function failureFunc() { console.log( "failure!" ); } $.when( $.ajax( "/main.php" ), $.ajax( "/modules.php" ), $.ajax( "/lists.php" ) ).then( successFunc, failureFunc ); ~~~ The following code example that uses many deferred features. This very basic script begins by consuming * (1) an external news feed * (2) a reactions feed for pulling in the latest comments via $.get() (which will return a promise-like object). ~~~JavaScript function getLatestNews() { return $.get( "latestNews.php", function( data ) { console.log( "news data received" ); $( ".news" ).html( data ); }); } function getLatestReactions() { return $.get( "latestReactions.php", function( data ) { console.log( "reactions data received" ); $( ".reactions" ).html( data ); }); } function showAjaxedContent() { // The .promise() is resolved *once*, after all animations complete return $( ".news, .reactions" ).slideDown( 500, function() { // Called once *for each element* when animation completes $(this).addClass( "active" ); }).promise(); } function removeActiveClass() { return $.Deferred(function( dfd ) { setTimeout(function () { $( ".news, .reactions" ).removeClass( "active" ); dfd.resolve(); }, 4000); }).promise(); } $.when( getLatestNews(), getLatestReactions() ) .then(showAjaxedContent) .then(removeActiveClass) .then(function() { console.log( "Requests succeeded and animations completed" ); }).fail(function() { console.log( "something went wrong!" ); }); ~~~ When both requests are received, the `showAjaxedContent()` function is called. The `showAjaxedContent()` function returns a promise that is resolved when animating both containers has completed. When the `showAjaxedContent()` promise is resolved, `removeActiveClass()` is called. The `removeActiveClass()` returns a promise that is resolved inside a `setTimeout()` after 4 seconds have elapsed. Finally, after the `removeActiveClass()` promise is resolved, the last `then()` callback is called, provided no errors occurred along the way. ### $.when [【官方文档】](https://api.jquery.com/jQuery.when/#jQuery-when-deferreds) ### 6.2 属性 #### 6.2.1 属性 * attr(name|pro|key,val|fn) * removeAttr(name) * prop(n|p|k,v|f) * removeProp(name) ## X Event [link](http://learn.jquery.com/events/) ## X 进一步探索 ### 1. $.attr(), $.prop(), $.datat()三者之间的区别于联系 ### 2. 异步编程/结构 * Deffered Object(延迟对象) [官方网页说明:](https://www.jquery123.com/category/deferred-object/) The Deferred object, introduced in jQuery 1.5, is a chainable utility object created by calling the `jQuery.Deferred()` method. It can register multiple callbacks into callback queues, invoke callback queues, and relay the success or failure state of any synchronous or asynchronous function. The Deferred object is chainable, similar to the way a jQuery object is chainable, but it has its own methods. After creating a Deferred object, you can use any of the methods below by either chaining directly from the object creation or saving the object in a variable and invoking one or more methods on that variable. | deferred方法 | 说明 | 类型 | | --- | --- | --- | | deferred.always() | 当Deferred(延迟)对象解决或拒绝时,调用添加处理程序。 | 延迟对象 | | deferred.catch() | Add handlers to be called when the Deferred object is rejected. | 延迟对象 | | deferred.done() | 当Deferred(延迟)对象解决时,调用添加处理程序。 | 延迟对象| | deferred.fail() | 当Deferred(延迟)对象拒绝时,调用添加的处理程序。 | 延迟对象| | deferred.notify() | 根据给定的 args参数 调用Deferred(延迟)对象上进行中的回调 (progressCallbacks)。 | 延迟对象 | | deferred.notifyWith() | 根据给定的上下文(context)和args递延调用Deferred(延迟)对象上进行中的回调(progressCallbacks )。 | 延迟对象 | | deferred.progress() | 当Deferred(延迟)对象生成进度通知时,调用添加处理程序。 | 延迟对象 | | deferred.promise() | 返回Deferred(延迟)的Promise(承诺)对象。 | 延迟对象 | | deferred.reject() | 拒绝Deferred(延迟)对象,并根据给定的args参数调用任何失败回调函数(failCallbacks)。 | 延迟对象 | | deferred.rejectWith() | 拒绝Deferred(延迟)对象,并根据给定的 context和args参数调用任何失败回调函数(failCallbacks)。 | 延迟对象 | | deferred.resolve() | 解决Deferred(延迟)对象,并根据给定的args参数调用任何完成回调函数(doneCallbacks)。 | 延迟对象 | | deferred.resolveWith() | 解决Deferred(延迟)对象,并根据给定的 context和args参数调用任何完成回调函数(doneCallbacks)。 | 延迟对象 | | deferred.state() | 确定一个Deferred(延迟)对象的当前状态。 | 延迟对象 | | deferred.then() | 当Deferred(延迟)对象解决,拒绝或仍在进行中时,调用添加处理程序。 | 延迟对象 | | jQuery.Deferred() | 一个构造函数,返回一个链式实用对象方法来注册多个回调,回调队列, 调用回调队列,并转达任何同步或异步函数的成功或失败状态。 | 延迟对象 | | jQuery.when() | 提供一种方法来执行一个或多个对象的回调函数, Deferred(延迟)对象通常表示异步事件。 | 核心 API 、 延迟对象 | | .promise() |返回一个 Promise 对象,用来观察当某种类型的所有行动绑定到集合,排队与否还是已经完成。| 延迟对象 | * $.when()then() ~~~JavaScript $.when( ajaxFunc1, ajaxFunc2, ..... ).then( successFunc, failFunc ); ~~~ * $.promise()