選擇器
選擇器是jQuery的核心。
按ID查找
如果某個DOM節點有id屬性,利用jQuery查找如下:
// 查找<div id="abc">:
var div = $('#abc');
注意,#abc以#開頭。返回的對象是jQuery對象。
什么是jQuery對象?jQuery對象類似數組,它的每個元素都是一個引用了DOM節點的對象。
以上面的查找為例,如果id為abc的<div>存在,返回的jQuery對象如下:
[<div id="abc">...</div>]
如果id為abc的<div>不存在,返回的jQuery對象如下:
[]
總之jQuery的選擇器不會返回undefined或者null,這樣的好處是你不必在下一行判斷if (div === undefined)。
jQuery對象和DOM對象之間可以互相轉化:
var div = $('#abc'); // jQuery對象
var divDom = div.get(0); // 假設存在div,獲取第1個DOM元素
var another = $(divDom); // 重新把DOM包裝為jQuery對象
通常情況下你不需要獲取DOM對象,直接使用jQuery對象更加方便。如果你拿到了一個DOM對象,那可以簡單地調用$(aDomObject)把它變成jQuery對象,這樣就可以方便地使用jQuery的API了。
按tag查找
按tag查找只需要寫上tag名稱就可以了:
var ps = $('p'); // 返回所有<p>節點
ps.length; // 數一數頁面有多少個<p>節點
按class查找(點.)
按class查找注意在class名稱前加一個.:
var a = $('.red'); // 所有節點包含`class="red"`都將返回
// 例如:
// <div class="red">...</div>
// <p class="green red">...</p>
通常很多節點有多個class,我們可以查找同時包含red和green的節點:
var a = $('.red.green'); // 注意沒有空格!
// 符合條件的節點:
// <div class="red green">...</div>
// <div class="blue green red">...</div>
按屬性查找(中括號[])
一個DOM節點除了id和class外還可以有很多屬性,很多時候按屬性查找會非常方便,比如在一個表單中按屬性來查找:
var email = $('[name=email]'); // 找出<??? name="email">
var passwordInput = $('[type=password]'); // 找出<??? type="password">
var a = $('[items="A B"]'); // 找出<??? items="A B">
當屬性的值包含空格等特殊字符時,需要用雙引號括起來。
按屬性查找還可以使用前綴查找或者后綴查找(中括號[]+^或$)
var icons = $('[name^=icon]'); // 找出所有name屬性值以icon開頭的DOM
// 例如: name="icon-1", name="icon-2"
var names = $('[name$=with]'); // 找出所有name屬性值以with結尾的DOM
// 例如: name="startswith", name="endswith"
這個方法尤其適合通過class屬性查找,且不受class包含多個名稱的影響:
var icons = $('[class^="icon-"]'); // 找出所有class包含至少一個以`icon-`開頭的DOM
// 例如: class="icon-clock", class="abc icon-home"
組合查找(標簽+中括號[])
組合查找就是把上述簡單選擇器組合起來使用。如果我們查找$('[name=email]'),很可能把表單外的<div name="email">也找出來,但我們只希望查找<input>,就可以這么寫:
var emailInput = $('input[name=email]'); // 不會找出<div name="email">
同樣的,根據tag和class來組合查找也很常見:
var tr = $('tr.red'); // 找出<tr class="red ...">...</tr>
多項選擇器(逗號,)
多項選擇器就是把多個選擇器用,組合起來一塊選:
$('p,div'); // 把<p>和<div>都選出來
$('p.red,p.green'); // 把<p class="red">和<p class="green">都選出來
要注意的是,選出來的元素是按照它們在HTML中出現的順序排列的,而且不會有重復元素。例如,<p class="red green">不會被上面的$('p.red,p.green')選擇兩次。
層級選擇器(空格)
如果兩個DOM元素具有層級關系,就可以用$('ancestor descendant')來選擇,層級之間用空格隔開。
子選擇器(大于號>)
子選擇器$('parent>child')類似層級選擇器,但是限定了層級關系必須是父子關系,就是<child>節點必須是<parent>節點的直屬子節點。
過濾器(冒號:)
過濾器一般不單獨使用,它通常附加在選擇器上,幫助我們更精確地定位元素。觀察過濾器的效果:
$('ul.lang li'); // 選出JavaScript、Python和Lua 3個節點
$('ul.lang li:first-child'); // 僅選出JavaScript
$('ul.lang li:last-child'); // 僅選出Lua
$('ul.lang li:nth-child(2)'); // 選出第N個元素,N從1開始
$('ul.lang li:nth-child(even)'); // 選出序號為偶數的元素
$('ul.lang li:nth-child(odd)'); // 選出序號為奇數的元素
針對表單元素,jQuery還有一組特殊的選擇器:
:input:可以選擇<input>,<textarea>,<select>和<button>;
:file:可以選擇<input type="file">,和input[type=file]一樣;
:checkbox:可以選擇復選框,和input[type=checkbox]一樣;
:radio:可以選擇單選框,和input[type=radio]一樣;
:focus:可以選擇當前輸入焦點的元素,例如把光標放到一個<input>上,用$('input:focus')就可以選出;
:checked:選擇當前勾上的單選框和復選框,用這個選擇器可以立刻獲得用戶選擇的項目,如$('input[type=radio]:checked');
:enabled:可以選擇可以正常輸入的<input>、<select>等,也就是沒有灰掉的輸入;
:disabled:和:enabled正好相反,選擇那些不能輸入的。
此外,jQuery還有很多有用的選擇器,例如,選出可見的或隱藏的元素:
$('div:visible'); // 所有可見的div
$('div:hidden'); // 所有隱藏的div
查找
最常見的查找是在某個節點的所有子節點中查找,使用find()方法,它本身又接收一個任意的選擇器。例如如下的HTML結構:
<!-- HTML結構 -->
<ul class="lang">
<li class="js dy">JavaScript</li>
<li class="dy">Python</li>
<li id="swift">Swift</li>
<li class="dy">Scheme</li>
<li name="haskell">Haskell</li>
</ul>
用find()查找:
var ul = $('ul.lang'); // 獲得<ul>
var dy = ul.find('.dy'); // 獲得JavaScript, Python, Scheme
var swf = ul.find('#swift'); // 獲得Swift
var hsk = ul.find('[name=haskell]'); // 獲得Haskell
如果要從當前節點開始向上查找,使用parent()方法:
var swf = $('#swift'); // 獲得Swift
var parent = swf.parent(); // 獲得Swift的上層節點<ul>
var a = swf.parent('div.red'); // 從Swift的父節點開始向上查找,直到找到某個符合條件的節點并返回
對于位于同一層級的節點,可以通過next()和prev()方法,例如:
當我們已經拿到Swift節點后:
var swift = $('#swift');
swift.next(); // Scheme
swift.next('[name=haskell]'); // Haskell,因為Haskell是后續第一個符合選擇器條件的節點
swift.prev(); // Python
swift.prev('.js'); // JavaScript,因為JavaScript是往前第一個符合選擇器條件的節點
過濾
和函數式編程的map、filter類似,jQuery對象也有類似的方法。
filter()方法可以過濾掉不符合選擇器條件的節點:
var langs = $('ul.lang li'); // 拿到JavaScript, Python, Swift, Scheme和Haskell
var a = langs.filter('.dy'); // 拿到JavaScript, Python, Scheme
或者傳入一個函數,要特別注意函數內部的this被綁定為DOM對象,不是jQuery對象:
var langs = $('ul.lang li'); // 拿到JavaScript, Python, Swift, Scheme和Haskell
langs.filter(function () {
return this.innerHTML.indexOf('S') === 0; // 返回S開頭的節點
}); // 拿到Swift, Scheme
map()方法把一個jQuery對象包含的若干DOM節點轉化為其他對象:
var langs = $('ul.lang li'); // 拿到JavaScript, Python, Swift, Scheme和Haskell
var arr = langs.map(function () {
return this.innerHTML;
}).get(); // 用get()拿到包含string的Array:['JavaScript', 'Python', 'Swift', 'Scheme', 'Haskell']
此外,一個jQuery對象如果包含了不止一個DOM節點,first()、last()和slice()方法可以返回一個新的jQuery對象,把不需要的DOM節點去掉:
var langs = $('ul.lang li'); // 拿到JavaScript, Python, Swift, Scheme和Haskell
var js = langs.first(); // JavaScript,相當于$('ul.lang li:first-child')
var haskell = langs.last(); // Haskell, 相當于$('ul.lang li:last-child')
var sub = langs.slice(2, 4); // Swift, Scheme, 參數和數組的slice()方法一致
操作DOM
修改Text和HTML
jQuery對象的text()和html()方法分別獲取節點的文本和原始HTML文本,例如,如下的HTML結構:
<!-- HTML結構 -->
<ul id="test-ul">
<li class="js">JavaScript</li>
<li name="book">Java & JavaScript</li>
</ul>
分別獲取文本和HTML:
$('#test-ul li[name=book]').text(); // 'Java & JavaScript'
$('#test-ul li[name=book]').html(); // 'Java & JavaScript'
如何設置文本或HTML?jQuery的API設計非常巧妙:無參數調用text()是獲取文本,傳入參數就變成設置文本,HTML也是類似操作
一個jQuery對象可以包含0個或任意個DOM對象,它的方法實際上會作用在對應的每個DOM節點上。在上面的例子中試試:
$('#test-ul li').text('JS'); // 是不是兩個節點都變成了JS?
所以jQuery對象的另一個好處是我們可以執行一個操作,作用在對應的一組DOM節點上。即使選擇器沒有返回任何DOM節點,調用jQuery對象的方法仍然不會報錯:
// 如果不存在id為not-exist的節點:
$('#not-exist').text('Hello'); // 代碼不報錯,沒有節點被設置為'Hello'
這意味著jQuery幫你免去了許多if語句。
修改CSS
jQuery對象有“批量操作”的特點,這用于修改CSS實在是太方便了。考慮下面的HTML結構:
<!-- HTML結構 -->
<ul id="test-css">
<li class="lang dy"><span>JavaScript</span></li>
<li class="lang"><span>Java</span></li>
<li class="lang dy"><span>Python</span></li>
<li class="lang"><span>Swift</span></li>
<li class="lang dy"><span>Scheme</span></li>
</ul>
注意,jQuery對象的所有方法都返回一個jQuery對象(可能是新的也可能是自身),這樣我們可以進行鏈式調用,非常方便。
jQuery對象的css()方法可以這么用:
var div = $('#test-div');
div.css('color'); // '#000033', 獲取CSS屬性
div.css('color', '#336699'); // 設置CSS屬性
div.css('color', ''); // 清除CSS屬性
為了和JavaScript保持一致,CSS屬性可以用'background-color'和'backgroundColor'兩種格式。
css()方法將作用于DOM節點的style屬性,具有最高優先級。如果要修改class屬性,可以用jQuery提供的下列方法:
var div = $('#test-div');
div.hasClass('highlight'); // false, class是否包含highlight
div.addClass('highlight'); // 添加highlight這個class
div.removeClass('highlight'); // 刪除highlight這個class
顯示和隱藏DOM
要隱藏一個DOM,我們可以設置CSS的display屬性為none,利用css()方法就可以實現。不過,要顯示這個DOM就需要恢復原有的display屬性,這就得先記下來原有的display屬性到底是block還是inline還是別的值。
考慮到顯示和隱藏DOM元素使用非常普遍,jQuery直接提供show()和hide()方法,我們不用關心它是如何修改display屬性的,總之它能正常工作:
var a = $('a[target=_blank]');
a.hide(); // 隱藏
a.show(); // 顯示
注意,隱藏DOM節點并未改變DOM樹的結構,它只影響DOM節點的顯示。這和刪除DOM節點是不同的。
獲取DOM信息
利用jQuery對象的若干方法,我們直接可以獲取DOM的高寬等信息,而無需針對不同瀏覽器編寫特定代碼:
// 瀏覽器可視窗口大小:
$(window).width(); // 800
$(window).height(); // 600
// HTML文檔大小:
$(document).width(); // 800
$(document).height(); // 3500
// 某個div的大小:
var div = $('#test-div');
div.width(); // 600
div.height(); // 300
div.width(400); // 設置CSS屬性 width: 400px,是否生效要看CSS是否有效
div.height('200px'); // 設置CSS屬性 height: 200px,是否生效要看CSS是否有效
attr()和removeAttr()方法用于操作DOM節點的屬性:
// <div id="test-div" name="Test" start="1">...</div>
var div = $('#test-div');
div.attr('data'); // undefined, 屬性不存在
div.attr('name'); // 'Test'
div.attr('name', 'Hello'); // div的name屬性變為'Hello'
div.removeAttr('name'); // 刪除name屬性
div.attr('name'); // undefined
prop()方法和attr()類似,但是HTML5規定有一種屬性在DOM節點中可以沒有值,只有出現與不出現兩種,例如:
<input id="test-radio" type="radio" name="test" checked value="1">
等價于:
<input id="test-radio" type="radio" name="test" checked="checked" value="1">
attr()和prop()對于屬性checked處理有所不同:
var radio = $('#test-radio');
radio.attr('checked'); // 'checked'
radio.prop('checked'); // true
prop()返回值更合理一些。不過,用is()方法判斷更好:
var radio = $('#test-radio');
radio.is(':checked'); // true
類似的屬性還有selected,處理時最好用is(':selected')。
操作表單
對于表單元素,jQuery對象統一提供val()方法獲取和設置對應的value屬性:
/*
<input id="test-input" name="email" value="">
<select id="test-select" name="city">
<option value="BJ" selected>Beijing</option>
<option value="SH">Shanghai</option>
<option value="SZ">Shenzhen</option>
</select>
<textarea id="test-textarea">Hello</textarea>
*/
var
input = $('#test-input'),
select = $('#test-select'),
textarea = $('#test-textarea');
input.val(); // 'test'
input.val('abc@example.com'); // 文本框的內容已變為abc@example.com
select.val(); // 'BJ'
select.val('SH'); // 選擇框已變為Shanghai
textarea.val(); // 'Hello'
textarea.val('Hi'); // 文本區域已更新為'Hi'
可見,一個val()就統一了各種輸入框的取值和賦值的問題。
事件
由于不同的瀏覽器綁定事件的代碼都不太一樣,所以用jQuery來寫代碼,就屏蔽了不同瀏覽器的差異,我們總是編寫相同的代碼。
舉個例子,假設要在用戶點擊了超鏈接時彈出提示框,我們用jQuery這樣綁定一個click事件:
/* HTML:
*
* <a id="test-link" href="#0">點我試試</a>
*
*/
// 獲取超鏈接的jQuery對象:
var a = $('#test-link');
a.on('click', function () {
alert('Hello!');
});
實測:點我試試
on方法用來綁定一個事件,我們需要傳入事件名稱和對應的處理函數。
另一種更簡化的寫法是直接調用click()方法:
a.click(function () {
alert('Hello!');
});
兩者完全等價。我們通常用后面的寫法。
jQuery能夠綁定的事件主要包括:
鼠標事件
click: 鼠標單擊時觸發;
dblclick:鼠標雙擊時觸發;
mouseenter:鼠標進入時觸發;
mouseleave:鼠標移出時觸發;
mousemove:鼠標在DOM內部移動時觸發;
hover:鼠標進入和退出時觸發兩個函數,相當于mouseenter加上mouseleave。
鍵盤事件
鍵盤事件僅作用在當前焦點的DOM上,通常是<input>和<textarea>。
keydown:鍵盤按下時觸發;
keyup:鍵盤松開時觸發;
keypress:按一次鍵后觸發。
其他事件
focus:當DOM獲得焦點時觸發;
blur:當DOM失去焦點時觸發;
change:當<input>、<select>或<textarea>的內容改變時觸發;
submit:當<form>提交時觸發;
ready:當頁面被載入并且DOM樹完成初始化后觸發。
其中,ready僅作用于document對象。由于ready事件在DOM完成初始化后觸發,且只觸發一次,所以非常適合用來寫其他的初始化代碼。假設我們想給一個<form>表單綁定submit事件,下面的代碼沒有預期的效果:
<html>
<head>
<script>
// 代碼有誤:
$('#testForm).on('submit', function () {
alert('submit!');
});
</script>
</head>
<body>
<form id="testForm">
...
</form>
</body>
因為JavaScript在此執行的時候,<form>尚未載入瀏覽器,所以$('#testForm)返回[],并沒有綁定事件到任何DOM上。
所以我們自己的初始化代碼必須放到document對象的ready事件中,保證DOM已完成初始化:
<html>
<head>
<script>
$(document).on('ready', function () {
$('#testForm).on('submit', function () {
alert('submit!');
});
});
</script>
</head>
<body>
<form id="testForm">
...
</form>
</body>
這樣寫就沒有問題了。因為相關代碼會在DOM樹初始化后再執行。
由于ready事件使用非常普遍,所以可以這樣簡化:
$(document).ready(function () {
// on('submit', function)也可以簡化:
$('#testForm).submit(function () {
alert('submit!');
});
});
甚至還可以再簡化為:
$(function () {
// init...
});
上面的這種寫法最為常見。如果你遇到$(function () {...})的形式,牢記這是document對象的ready事件處理函數。
完全可以反復綁定事件處理函數,它們會依次執行:
$(function () {
console.log('init A...');
});
$(function () {
console.log('init B...');
});
$(function () {
console.log('init C...');
});
事件參數
有些事件,如mousemove和keypress,我們需要獲取鼠標位置和按鍵的值,否則監聽這些事件就沒什么意義了。所有事件都會傳入Event對象作為參數,可以從Event對象上獲取到更多的信息:
$(function () {
$('#testMouseMoveDiv').mousemove(function (e) {
$('#testMouseMoveSpan').text('pageX = ' + e.pageX + ', pageY = ' + e.pageY);
});
});
取消綁定
一個已被綁定的事件可以解除綁定,通過off('click', function)實現:
function hello() {
alert('hello!');
}
a.click(hello); // 綁定事件
// 10秒鐘后解除綁定:
setTimeout(function () {
a.off('click', hello);
}, 10000);
需要特別注意的是,下面這種寫法是無效的:
// 綁定事件:
a.click(function () {
alert('hello!');
});
// 解除綁定:
a.off('click', function () {
alert('hello!');
});
這是因為兩個匿名函數雖然長得一模一樣,但是它們是兩個不同的函數對象,off('click', function () {...})無法移除已綁定的第一個匿名函數。
為了實現移除效果,可以使用off('click')一次性移除已綁定的click事件的所有處理函數。
同理,無參數調用off()一次性移除已綁定的所有類型的事件處理函數。
事件觸發條件
一個需要注意的問題是,事件的觸發總是由用戶操作引發的。例如,我們監控文本框的內容改動:
var input = $('#test-input');
input.change(function () {
console.log('changed...');
});
當用戶在文本框中輸入時,就會觸發change事件。但是,如果用JavaScript代碼去改動文本框的值,將不會觸發change事件:
var input = $('#test-input');
input.val('change it!'); // 無法觸發change事件
有些時候,我們希望用代碼觸發change事件,可以直接調用無參數的change()方法來觸發該事件:
var input = $('#test-input');
input.val('change it!');
input.change(); // 觸發change事件
input.change()相當于input.trigger('change'),它是trigger()方法的簡寫。
為什么我們希望手動觸發一個事件呢?如果不這么做,很多時候,我們就得寫兩份一模一樣的代碼。
瀏覽器安全限制
在瀏覽器中,有些JavaScript代碼只有在用戶觸發下才能執行,例如,window.open()函數:
// 無法彈出新窗口,將被瀏覽器屏蔽:
$(function () {
window.open('/');
});
這些“敏感代碼”只能由用戶操作來觸發:
var button1 = $('#testPopupButton1');
var button2 = $('#testPopupButton2');
function popupTestWindow() {
window.open('/');
}
button1.click(function () {
popupTestWindow();
});
button2.click(function () {
// 不立刻執行popupTestWindow(),100毫秒后執行:
setTimeout(popupTestWindow, 100);
});
當用戶點擊button1時,click事件被觸發,由于popupTestWindow()在click事件處理函數內執行,這是瀏覽器允許的,而button2的click事件并未立刻執行popupTestWindow(),延遲執行的popupTestWindow()將被瀏覽器攔截。
動畫
jQuery內置的幾種動畫樣式:
show / hide/toggle
直接以無參數形式調用show()和hide(),會顯示和隱藏DOM元素。但是,只要傳遞一個時間參數進去,就變成了動畫:
var div = $('#test-show-hide');
div.hide(3000); // 在3秒鐘內逐漸消失
時間以毫秒為單位,但也可以是'slow','fast'這些字符串:
var div = $('#test-show-hide');
div.show('slow'); // 在0.6秒鐘內逐漸顯示
toggle()方法則根據當前狀態決定是show()還是hide()。
slideUp / slideDown/slideToggle
你可能已經看出來了,show()和hide()是從左上角逐漸展開或收縮的,而slideUp()和slideDown()則是在垂直方向逐漸展開或收縮的。
slideUp()把一個可見的DOM元素收起來,效果跟拉上窗簾似的,slideDown()相反,而slideToggle()則根據元素是否可見來決定下一步動作:
var div = $('#test-slide');
div.slideUp(3000); // 在3秒鐘內逐漸向上消失
fadeIn / fadeOut/fadeToggle
fadeIn()和fadeOut()的動畫效果是淡入淡出,也就是通過不斷設置DOM元素的opacity屬性來實現,而fadeToggle()則根據元素是否可見來決定下一步動作:
var div = $('#test-fade');
div.fadeOut('slow'); // 在0.6秒內淡出
自定義動畫
如果上述動畫效果還不能滿足你的要求,那就祭出最后大招:animate(),它可以實現任意動畫效果,我們需要傳入的參數就是DOM元素最終的CSS狀態和時間,jQuery在時間段內不斷調整CSS直到達到我們設定的值:
var div = $('#test-animate');
div.animate({
opacity: 0.25,
width: '256px',
height: '256px'
}, 3000); // 在3秒鐘內CSS過渡到設定值
animate()還可以再傳入一個函數,當動畫結束時,該函數將被調用:
var div = $('#test-animate');
div.animate({
opacity: 0.25,
width: '256px',
height: '256px'
}, 3000, function () {
console.log('動畫已結束');
// 恢復至初始狀態:
$(this).css('opacity', '1.0').css('width', '128px').css('height', '128px');
});
實際上這個回調函數參數對于基本動畫也是適用的。
串行動畫
jQuery的動畫效果還可以串行執行,通過delay()方法還可以實現暫停,這樣,我們可以實現更復雜的動畫效果,而代碼卻相當簡單:
var div = $('#test-animates');
// 動畫效果:slideDown - 暫停 - 放大 - 暫停 - 縮小
div.slideDown(2000)
.delay(1000)
.animate({
width: '256px',
height: '256px'
}, 2000)
.delay(1000)
.animate({
width: '128px',
height: '128px'
}, 2000);
}
</script>
因為動畫需要執行一段時間,所以jQuery必須不斷返回新的Promise對象才能后續執行操作。簡單地把動畫封裝在函數中是不夠的。
為什么有的動畫沒有效果
你可能會遇到,有的動畫如slideUp()根本沒有效果。這是因為jQuery動畫的原理是逐漸改變CSS的值,如height從100px逐漸變為0。但是很多不是block性質的DOM元素,對它們設置height根本就不起作用,所以動畫也就沒有效果。
此外,jQuery也沒有實現對background-color的動畫效果,用animate()設置background-color也沒有效果。這種情況下可以使用CSS3的transition實現動畫效果。
擴展
編寫jQuery插件
給jQuery對象綁定一個新方法是通過擴展$.fn對象實現的。讓我們來編寫第一個擴展——highlight1():
$.fn.highlight1 = function () {
// this已綁定為當前jQuery對象:
this.css('backgroundColor', '#fffceb').css('color', '#d85030');
return this;
}
注意到函數內部的this在調用時被綁定為jQuery對象,所以函數內部代碼可以正常調用所有jQuery對象的方法。
對于如下的HTML結構:
<!-- HTML結構 -->
<div id="test-highlight1">
<p>什么是<span>jQuery</span></p>
<p><span>jQuery</span>是目前最流行的<span>JavaScript</span>庫。</p>
</div>
為什么最后要return this;?因為jQuery對象支持鏈式操作,我們自己寫的擴展方法也要能繼續鏈式下去:
$('span.hl').highlight1().slideDown();
不然,用戶調用的時候,就不得不把上面的代碼拆成兩行。
但是這個版本并不完美。有的用戶希望高亮的顏色能自己來指定,怎么辦?
我們可以給方法加個參數,讓用戶自己把參數用對象傳進去。于是我們有了第二個版本的highlight2():
$.fn.highlight2 = function (options) {
// 要考慮到各種情況:
// options為undefined
// options只有部分key
var bgcolor = options && options.backgroundColor || '#fffceb';
var color = options && options.color || '#d85030';
this.css('backgroundColor', bgcolor).css('color', color);
return this;
}
對于默認值的處理,我們用了一個簡單的&&和||短路操作符,總能得到一個有效的值。
另一種方法是使用jQuery提供的輔助方法$.extend(target, obj1, obj2, ...),它把多個object對象的屬性合并到第一個target對象中,遇到同名屬性,總是使用靠后的對象的值,也就是越往后優先級越高:
// 把默認值和用戶傳入的options合并到對象{}中并返回:
var opts = $.extend({}, {
backgroundColor: '#00a8e6',
color: '#ffffff'
}, options);
緊接著用戶對highlight2()提出了意見:每次調用都需要傳入自定義的設置,能不能讓我自己設定一個缺省值,以后的調用統一使用無參數的highlight2()?
也就是說,我們設定的默認值應該能允許用戶修改。
那默認值放哪比較合適?放全局變量肯定不合適,最佳地點是$.fn.highlight2這個函數對象本身。
于是最終版的highlight()終于誕生了:
$.fn.highlight = function (options) {
// 合并默認值和用戶設定值:
var opts = $.extend({}, $.fn.highlight.defaults, options);
this.css('backgroundColor', opts.backgroundColor).css('color', opts.color);
return this;
}
// 設定默認值:
$.fn.highlight.defaults = {
color: '#d85030',
backgroundColor: '#fff8de'
}
這次用戶終于滿意了。用戶使用時,只需一次性設定默認值:
$.fn.highlight.defaults.color = '#fff';
$.fn.highlight.defaults.backgroundColor = '#000';
然后就可以非常簡單地調用highlight()了。