点击事件与事件冒泡异常:点击li触发两次alert问题
问题分析与解决
场景与问题
现有WPForms单选框的HTML结构如下:
<div id="wpforms-1345-field_6-container" class="wpforms-field wpforms-field-radio row-selection" data-field-id="6"> <label class="wpforms-field-label" for="wpforms-1345-field_6">What is your age? <span class="wpforms-required-label">*</span> </label> <ul id="wpforms-1345-field_6" class="wpforms-field-required"> <li class="choice-1 depth-1"> <input type="radio" id="wpforms-1345-field_6_1" name="wpforms[fields][6]" value="0-15" required=""> <label class="wpforms-field-label-inline" for="wpforms-1345-field_6_1">0-15</label> </li> <li class="choice-2 depth-1"> <input type="radio" id="wpforms-1345-field_6_2" name="wpforms[fields][6]" value="16-25" required=""> <label class="wpforms-field-label-inline" for="wpforms-1345-field_6_2">16-25</label> </li> <li class="choice-3 depth-1"> <input type="radio" id="wpforms-1345-field_6_3" name="wpforms[fields][6]" value="26-35" required=""> <label class="wpforms-field-label-inline" for="wpforms-1345-field_6_3">26-35</label> </li> <li class="choice-5 depth-1"> <input type="radio" id="wpforms-1345-field_6_5" name="wpforms[fields][6]" value="36-45" required=""> <label class="wpforms-field-label-inline" for="wpforms-1345-field_6_5">36-45</label> </li> <li class="choice-4 depth-1"> <input type="radio" id="wpforms-1345-field_6_4" name="wpforms[fields][6]" value="46-100" required=""> <label class="wpforms-field-label-inline" for="wpforms-1345-field_6_4">≥46</label> </li> </ul> </div>
需求是点击<li>即可选中对应的单选框,但无法修改现有HTML结构。编写的jQuery代码如下:
jQuery(function($) { $('.row-selection li').on('click', function(event) { alert('clicked'); // event.preventDefault(); event.stopPropagation(); $(this).children('input')[0].click(function(event) { alert('bubbledup'); // event.preventDefault(); event.stopPropagation(); }); }); });
实际运行时出现两个问题:
- 点击
<li>会触发两次clicked弹窗; bubbledup弹窗从未触发。
原因拆解
两次弹窗的根源
点击<li>内的<label>时,浏览器会因为<label>的for属性自动触发关联<input>的点击事件。而<input>是<li>的子元素,这个点击事件会向上冒泡到<li>,导致<li>的点击事件被触发两次:一次是点击<label>或<li>空白处的原始事件,另一次是<label>触发<input>点击后冒泡上来的事件。你添加的event.stopPropagation()只阻止了当前事件向上冒泡,没处理<label>触发的额外事件流。bubbledup不触发的原因
你在<li>的点击事件里才给<input>绑定点击回调,而同步触发input.click()时,这个回调还没绑定完成,自然不会执行。而且这种绑定方式会导致每次点击<li>都给<input>新增一个点击事件,属于错误用法。
修正后的代码
jQuery(function($) { $('.row-selection li').on('click', function(event) { // 排除点击input本身的情况,避免重复操作 if (event.target.tagName !== 'INPUT') { const $radio = $(this).find('input[type="radio"]'); $radio.prop('checked', true); // 触发change事件,保证表单数据同步 $radio.trigger('change'); } event.stopPropagation(); }); // 阻止label的默认行为,避免自动触发input点击导致重复事件 $('.row-selection li label').on('click', function(event) { event.preventDefault(); }); });
内容的提问来源于stack exchange,提问作者Faye D.
相关产品推荐
相关产品推荐

