click事件執行兩次這麼皮??
在專案中遇到一個小bug—— label
標籤上綁定了一個返回一層路由的點選事件,然而每次點選都會返回兩層!!
經除錯發現, label
標籤中包裹 input
,而事件繫結在 label
標籤中時,點選 label
區域,事件會執行兩次。
問題測試
<label onclick="labelConsole()"> <input type="checkbox" onclick="inputConsole()">勾選協議 </label> 複製程式碼
function labelConsole (){ console.log('label_click 這是我們想要的操作') } function inputConsole (){ console.log('input_click') } 複製程式碼
- 點選
label
區域(不直接點選input
區域):label
上的事件被觸發執行一次,同時子元素input
本身也繫結有click事件,觸發後又冒泡傳遞給label
,又觸發了一次label
繫結事件。

- 直接點選
input
區域:觸發input
繫結事件後又冒泡傳遞給label
,觸發了label
的繫結事件。

分析原因
- 元素預設繫結click事件
一些元素如 <a>
、 <button>
、 <input>
本身就預設綁定了click事件,即使你不繫結,click事件發生時他們也會接收到。
-
label
標籤的擴充套件性
它把所包含的input的使用者互動區域擴充套件了,注意的是 label
和所包含的 input
都開始繫結預設事件,此時會發生事件冒泡現象。在 label上
的click事件的處理函式會觸發2次就是由於:第一次是 label
自己接收到事件,執行處理函式,第二次是 input
接受到事件後冒泡傳遞給 label
,再次觸發處理函式。
解決方案
方案1:將原綁定於label的事件,直接綁定於input上。
<label> <input type="checkbox" onclick="labelConsole()">勾選協議 </label> 複製程式碼

此時,當點選 label
區域或者直接點選 input
區域,由於 checkbox
本身有預設click監聽器,所以會觸發一次我們繫結的事件。
方案2:阻止事件冒泡
<label onclick="labelConsole()"> <input type="checkbox" onclick="inputConsole()">勾選協議 </label> 複製程式碼
function labelConsole (){ console.log('label_click 這是我們想要的操作') } function inputConsole (){ console.log('input_click'); window.event? window.event.cancelBubble = true : e.stopPropagation(); } 複製程式碼

點選 label
非 input
區域的時候效果如上,這種方法看似實現了我們的需求,只讓我們想要的操作觸發一次,但是如果你直接點選的是input,那就跪了。
沒錯,當你直接點選 input
的時候只會觸發 input
的繫結事件,而我們繫結在label上的事件則無人問津。這並不符合預期,所以方案2不太可取,最後採取方案1。