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()
- WebAPP
- Linux Command
- 入門
- 處理文件
- 查找文件單詞
- 環境
- 聯網
- Linux
- Linux目錄配置標準:FHS
- Linux文件與目錄管理
- Linux賬號管理與ACL權限設置
- Linux系統資源查看
- 軟件包管理
- Bash
- Daemon/Systemd
- ftp
- Apache
- MySQL
- Command
- Replication
- mysqld
- remote access
- remark
- 限制
- PHP
- String
- Array
- Function
- Class
- File
- JAVA
- Protocals
- http
- mqtt
- IDE
- phpDesigner
- eclipse
- vscode
- Notepad++
- WebAPI
- Javasript
- DOM
- BOM
- Event
- Class
- Module
- Ajax
- Fetch
- Promise
- async/await
- Statements and declarations
- Function
- Framwork
- jQurey
- Types
- Promise
- BootStrap
- v4
- ThinkPHP5
- install
- 定時任務
- CodeIgniter
- React.js
- node.js
- npm
- npm-commands
- npm-folder
- package.json
- Docker and private modules
- module
- webpack.js
- install
- configuration
- package.json
- entry
- modules
- plugins
- Code Splitting
- loaders
- libs
- API
- webpack-cli
- Vue.js
- install
- Compile
- VueAPI
- vuex
- vue-router
- vue-devtools
- vue-cli
- vue-loader
- VDOM
- vue-instance
- components
- template
- Single-File Components
- props
- data
- methods
- computed
- watch
- Event-handling
- Render Func
- remark
- 案例學習
- bootstrap-vue
- modal
- fontAwesome
- Hosting Font Awesome Yourself
- using with jquery
- using with Vue.js
- HTML
- CSS
- plugins
- Chart.js
- D3.js
- phpSpreadSheet
- Guzzle
- Cmder
- Git
- git命令
- git流程
- Postman
- Markdown
- Regular Expressions
- PowerDesigner
- 附錄1-學習資源