像上面這樣的例子會讓使用者養成使用「return false」來阻止瀏覽器執行預設行為的壞習慣,在這篇文章裡,我將會討論關於阻止瀏覽器執行預設行為的兩個非常重要的主題:
「return false」之所以被誤用的如此厲害,是因為它看起來像是完成了我們交給它的工作,瀏覽器不會再將我們重定向到href中的鏈接,表單也不會被繼續提交,但這麼做到底有什麼不對呢?
這3件事中用來阻止瀏覽器繼續執行預設行為的只有preventDefault,除非你想要停止事件冒泡,否則使用return false會為你的程式碼埋下很大的隱患,讓我們通過一個真實的例子來看看這樣的誤用會造成什麼後果:
$("div.post h2 a").click(function () {
var a = $(this),
href = a.attr('href'), // Let jQuery normalize `href`,
. content.load(href " #content");
return false; // "cancel" the default behavior of following the link
});
});
這段程式碼可以正常工作(至少目前是),但如果我們順著這個思路繼續,如果我想要在使用者點擊了一個div.post元素(或任何一個它的子元素)時,給它加上一個active類,我就需要給div.post增加了一個
click回調:
// Inside Document Ready:
var posts = $("div.post");
posts.click(function () {
Remove active from all div.post
posts.removeClass("active");
// Add it back to this one
$(this).addClass("active");
) ;
現在,如果我們點選一個貼文的標題,這段程式碼會運作嗎?答案是不會,因為我們在標題的click回調裡使用了return false而不是我們應該使用的,」return false「等於event.preventDefault();加event.stopPropagation();,所以事件冒泡就被終止了,click事件不會被冒泡到div.post上,我們為它新增的事件回呼當然也就不會被呼叫了。
如果我們把它和live或delegate事件混在一起使用時,情況就更糟了。
$("a").click(function () {
// do something
return false;
});
$("a").live("click", function () {
$("a").live("click", function () { });
那我們真正需要的是什麼呢?
preventDefault()
大多數情況下,當你使用return false時,你其實真正需要的是e.preventDefault()。要使用e.preventDefault,你需要確保你傳遞了event參數到你的回掉函數中(在這個例子裡,就是那個e):
$("a").click(function (e) {
// e == our event data
e. preventDefault();
});
它會替我們完成所有工作,但不會阻止父節點繼續處理事件,要記住,你放在程式碼中的限制越少,你的程式碼就越靈活,也就越容易維護。
stopPropagation()
但有些情況下,你有可能需要停止事件冒泡,讓我們看看下面的例子:
複製程式碼
代碼如下:
Normal text and then a
link and then more text.
複製程式碼
程式碼如下:
$("div.post").click(function () {
// Do the first thing;
});
$("div.post a").click(function (e) {
// Don't cancel the browser's default action
// and don't bubble this event!
e.stopPropagation(); });
});
使用return false,div的click事件不會被觸發,但是使用者也不會到達他們點的那個連結。
複製程式碼 程式碼如下:
$("div a").click(function () {
// Do something
});
$("div a").click(function (e) {
// Do something else
e.stopImmediatePropagation();
});
$("div a").click(function> // THIS NEVER FIRES
});
$("div").click(function () {
// THIS NEVER FIRES
});
你可能會覺得這個例子看起來很彆扭,沒錯,儘管如此,但有時這的確會發生,如果你的代碼非常複雜,那麼不同的widgets和plugin就有可能在同一個對像上添加事件,如果遇到這種情況,那你就很有必要去理解和使用stopImmediatePropagation。
return false
只有當你同時需要preventDefault和stopPropagation,你的程式碼可以接受直到你的回呼執行完成才停止執行瀏覽器的預設行為,那你就可以使用」return false「。但我強烈建議你別在寫給其它jQuery開發者的演示程式碼中使用這個方法,因為這會造成更多誤用,只有在你確信非用不可的情況下再去使用”return false“。
選擇適當的位置
如果你使用了”return false“,它只會在你的回調函數執行結束才去取消瀏覽器的預設行為,但是使用e.preventDefault,我們有更多的選擇,它可以隨時停止瀏覽器執行預設動作,而不管你將它放在函數的哪個部分。
1. 開發階段,
你應該總是把它放在第一行。你最不想做的事情可能就是你正在調試將一個form改成ajax提交的時候,它卻已經被按照舊方法提交了。
2. 產品階段,
如果你採用了漸進增強(progressive enhancement),那就把它放到回調的結束位置,或者是邏輯終點,如果在一個普通頁面採用漸進增強,那你就需要在伺服器端考慮如果瀏覽器不支援JS時(或被停用時),對連結的click事件和表單的提交事件的處理。這裡的好處是,我們不考慮關閉JS的情況,只考慮支援js時的強狂,如果你的回調程式碼出錯拋出了異常,讓我們看看下面的程式碼:
$("a").click(function (e ) {
e.preventDefault(); // cancel default behavior
// Throws an error because `my` is undefined
$("body").append("body").append); 🎜> // The original link doesn't work AND the "cool"
// JavaScript has broken. The user is left with NOTHING!
});
現在🎜>現在🎜>我們看看同樣的事件,把preventDefault調用放在底部的效果:
複製代碼
代碼如下:> var data = {}; $("a").click(function (e) {
// Throws an error because `my` is undefined // Throws an error because `my` is undefined "body").append(data.my.link);
// This line is never reached, and your website
// falls back to using the `href` instead of this
// "cool" broken JavaScript!
e.preventDefault(); // cancel default behavior
});
這對表單提交也同樣有效,你可以更好的應對出錯的情況,別指望你的程式碼一直正常運作,在發生錯誤時有正確的應對總勝過假設程式碼不會出錯。
3.在產品階段,
如果功能這設計JS,那就還應該放在第一行。
記住,不必非得是函數的第一行,但是越早越好,這裡的原則是:如果函數的功能是透過JS實現的(不涉及服務端互動),那就沒必要考慮相容,在這種情況下,添加在第一行可以防止URL中出現#字符,但顯然,你還是應該盡可能多的增加些錯誤處理代碼,以防止用戶在出錯時變得不知所措。
結論
我希望這篇文章傳達的訊息足夠你在需要阻止瀏覽器執行預設行為時做出正確的選擇。記住,只有當你真的明白你在做什麼時,才使用”return false“,並確保你是在函數的正確位置調用了相應的程式碼。最後,盡可能保持程式碼的彈性,盡量不要再用「return false」了!