問(wèn)題描述
在項(xiàng)目中遇到一個(gè)bug——label標(biāo)簽上綁定了一個(gè)返回一層的點(diǎn)擊事件娘锁,然鵝每次點(diǎn)擊都會(huì)返回兩層牙寞!!
經(jīng)調(diào)試發(fā)現(xiàn),label標(biāo)簽中包裹input莫秆,而事件綁定在label標(biāo)簽中時(shí)间雀,點(diǎn)擊label區(qū)域,事件會(huì)執(zhí)行兩次镊屎。
問(wèn)題測(cè)試
<label onclick="labelConsole()">
<input type="checkbox" onclick="inputConsole()">勾選協(xié)議
</label>
function labelConsole (){
console.log('label_click 這是我們想要的操作')
}
function inputConsole (){
console.log('input_click')
}
-
點(diǎn)擊label區(qū)域(不直接點(diǎn)擊input區(qū)域):label上的事件被觸發(fā)執(zhí)行一次惹挟,同時(shí)子元素input本身也綁定有click事件,觸發(fā)后又冒泡傳遞給label缝驳,又觸發(fā)了一次label綁定事件连锯。
-
直接點(diǎn)擊input區(qū)域:觸發(fā)input綁定事件后又冒泡傳遞給label,觸發(fā)了label的綁定事件用狱。
分析原因
- 元素默認(rèn)綁定click事件
一些元素如<a>运怖、<button>、<input>本生就默認(rèn)綁定了click事件齿拂,即使你不綁定驳规,click事件發(fā)生時(shí)他們也會(huì)接收到。 - label標(biāo)簽的擴(kuò)展性
它把所包含的input的用戶(hù)交互區(qū)域擴(kuò)展了署海,注意的是label和所包含的input都開(kāi)始綁定默認(rèn)事件吗购,此時(shí)會(huì)發(fā)生事件冒泡現(xiàn)象医男。在label上的click事件的處理函數(shù)會(huì)觸發(fā)2次就是由于:第一次是label自己接收到事件,執(zhí)行處理函數(shù)捻勉,第二次是input接受到事件后冒泡傳遞給label镀梭,再次觸發(fā)處理函數(shù)。
解決方案
方案1:將原綁定于label的事件踱启,直接綁定于input上报账。
<label>
<input type="checkbox" onclick="labelConsole()">勾選協(xié)議
</label>
此時(shí),當(dāng)點(diǎn)擊label區(qū)域或者直接點(diǎn)擊input區(qū)域埠偿,由于checkbox本身有默認(rèn)click監(jiān)聽(tīng)器透罢,所以會(huì)觸發(fā)一次我們綁定的事件。
方案2:阻止事件冒泡
<label onclick="labelConsole()">
<input type="checkbox" onclick="inputConsole()">勾選協(xié)議
</label>
function labelConsole (){
console.log('label_click 這是我們想要的操作')
}
function inputConsole (){
console.log('input_click');
window.event? window.event.cancelBubble = true : e.stopPropagation();
}
點(diǎn)擊label非input區(qū)域的時(shí)候效果如上冠蒋,這種方法看似實(shí)現(xiàn)了我們的需求羽圃,只讓我們想要的操作觸發(fā)一次,但是如果你直接點(diǎn)擊的是input抖剿,那就跪了朽寞。沒(méi)錯(cuò),當(dāng)你直接點(diǎn)擊input的時(shí)候只會(huì)觸發(fā)input的綁定事件斩郎,而我們綁定在label上的事件則無(wú)人問(wèn)津脑融。這并不符合預(yù)期,所以方案2不太可取缩宜。