1. 程式人生 > >input type為checkbox或radio時的click預設事件

input type為checkbox或radio時的click預設事件

               

  在input中,如果type為checkbox或radio時,瀏覽器會將該input渲染成為系統的單選或多選元件,如果這時,我們在這個input上繫結click事件,那就要小心謹慎使用e.preventDefault()這個方法(jQuery中整合了這個方法使得它能夠相容去掉瀏覽器中的預設事件)。之所以要說謹慎使用,就是,如果你在這個事件的響應程式中判斷該checkbox是否選中時,得到的結果和真正的選中狀態會有所不同。下面先從一個簡單的示例說明這個現象。(為了簡單起見,我使用了jquery,他能節省選擇器部分的程式碼,但不影響本文需要說明的問題)。程式碼段如下:

複製程式碼
<script type
="text/javascript">window.onload=function(){    $('#chk').on('click',function(e){        e.preventDefault();        alert($(this).attr('checked'));    });}</script></head><body><input type="checkbox" id="chk" /></body>
複製程式碼

  示例很簡單,就是在一個checkbox上繫結一個click事件,這個click事件是判斷當前的checkbox是否選上了。通過在瀏覽器上實際執行,結果是,在滑鼠點選checkbox的時候,彈出checked。但是關掉alert之後,頁面上的checkbox是未選中的狀態。我們將這個form提交到後臺也是取不到值的。既然沒選上,那我們在alert的後面加上這句:$(this).attr('checked',true);讓它選上,重新整理下,再點選,你會發現,在我們關閉alert之後,頁面上的checkbox仍然是未選中的。問題就在這,我們通過程式選中了checkbox,為什麼在響應函式執行完之後,checkbox還是未選中的狀態呢?

  為解釋這個問題,我們需要修改上面的程式碼:

複製程式碼
window.onload=function(){    $('#chk').on('click',function(e){        e.preventDefault();        $(this).attr('checked',true);        alert($(this).attr('checked'));    });}
複製程式碼

上面的程式碼我們先將設定check為true的語句放到alert前面,執行下看看,當我們點選checkbox時:

  可以看到,在執行完$(this).attr('checked',true);後到alert時,checkbox的狀態是選中的,而且彈出的狀態也是checked,也就是說,這個時候,checkbox是選中的。但是為什麼我們在點選確定之後,checkbox又變回了未選中了呢?在相應事件結束之後,一定還有什麼東西讓它改回去了?其實,這是checkbox的預設click事件的做的。也許大家會問,我不是通過e.preventDefault()把預設事件去掉了嗎?為什麼還有預設事件?難道e.preventDefault()沒有生效?

  在這裡需要說明下:一般的預設事件,會在我們繫結的響應事件之後執行(這樣說不準確,預設事件和自己繫結的響應事件是在一起執行的,只不過,它的真正的作用一般會在所有事件內容做完之後才會體現出來,因此,在這就簡單理解成在繫結的事件之後執行吧)。有了這個說明,我們再來說下這個現象。這不是瀏覽器的bug,也不是沒有禁掉預設事件。由於checkbox是系統的元件,因此它的實現機理比較複雜,在這裡不討論,這個問題的主要原因是:checkbox的click事件的預設事件是將修改的選中狀態生效。解釋一下,如果在滑鼠點選之前,checkbox的狀態是選中,那麼在點選checkbox時,它會將當前的狀態取反即取消選中,然後執行響應事件,最後預設事件將這個狀態生效。

  上面的這個程式碼中,由於去掉了預設事件,因此,在執行響應事件時,checkbox確實選中了,alert出來的也是選中的,但是在事件結束時,由於沒有沒有預設事件,那麼這個checkbox就回到了點選之前的狀態。我們如果將input寫成:<input type="checkbox" id="chk" checked />,即在點選之前就選中它,那麼點選之後,checkbox就是選中的狀態了。當然,這個選中狀態不是因為$(this).attr('checked',true);造成的,而是沒有預設事件,它又重置回之前的狀態了。這裡我們將程式碼改成$(this).attr('checked',false);在執行完之後,仍然會是選中狀態的。

  這個問題充分體現出了預設事件的重要性,我們之前去掉過很多預設事件,但是大部分的預設事件如我們想象的那樣,去掉之後,基本功能就不存在了。但是checkbox的click預設事件不是讓它沒有反應,而是將修改後的狀態生效(注意:僅僅是click事件,mousedown和mouseup事件是沒有這個特點的)。因此,在我們不知道這個問題之前,如果禁掉了它的click事件,就會出現一些問題了。當然,這知識針對checkbox和radio而言。w3c的文件也證實了這一點,它的文件上有明確的說明:

Note: During the handling of a click event on an input element with a type attribute that has the value "radio" or "checkbox", some implementations may change the value of this property before the event is being dispatched in the document. If the default action of the event is canceled, the value of the property may be changed back to its original value. This means that the value of this property during the handling of click events is implementation dependent.

原文地址:http://www.w3.org/TR/DOM-Level-2-HTML/html.html#ID-6043025