javascript - 为什么在这个html/css/jquery中注册了两个点击事件

标签 javascript html jquery css jquery-events

我正在尝试设置复选框列表的样式。我添加了我的样式,它们在渲染时正确显示。单击复选框的标签时,我想添加一个类。这是我的标记和 here is the same in a jsfiddle .从我的fiddle可以看出,一次点击就注册了两个点击事件。为什么?

html:

<ul>
    <li>
        <label for="test_0" class="">
            <input id="test_0" name="offering_cycle" type="checkbox" value="1"> Fall
        </label>
    </li>
    <li>
        <label for="test_1" class="">
            <input id="test_1" name="offering_cycle" type="checkbox" value="2"> Spring
        </label>
    </li>
    <li>
        <label for="test_2" class="">
            <input id="test_2" name="offering_cycle" type="checkbox" value="3"> Summer
        </label>
    </li>
    <li>
        <label for="test_3" class="">
            <input id="test_3" name="offering_cycle" type="checkbox" value="4"> Other
        </label>
    </li>
</ul>

CSS:

ul {
    list-style-type:none;
}
label {
    position:relative;
    display:inline-block;
    padding-left:27px;
    height:25px;
}
label:before {
    display:block;
    position:absolute;
    top:-2px;
    margin-left:-28px;
    width:18px;
    height:18px;
    background-color:#fff;
    border-radius:5px;
    border:1px solid #ccc;
    text-align: center;
    color:#fff;
    font-size:18px;
    content:'a';
}
input {
    width:1px;
    height:1px;
    border:0;
    opacity:0;
    float:right;
}

jQuery:

$('label[for*=test_]').on('click',function(){
    $(this).toggleClass('testing');
});

最佳答案

标签的点击处理程序被调用两次的原因:

单击与输入关联的标签会触发两个单击事件。标签的第一个点击事件被触发。该点击事件的默认处理会导致为关联的输入触发第二个点击事件。由于您将输入作为标签的后代,因此第二个点击事件会冒泡到标签。这就是为什么您的点击事件处理程序被调用两次的原因。


如果您真的想处理标签的点击事件(并且只针对点击执行一次):

(1) 如果您愿意并且能够修改 HTML,您可以移动输入,使其不是标签的后代。仍然会有两个点击事件,但是第二个点击事件不会从输入冒泡到标签,因为标签不再是输入的祖先。

当输入不是标签的后代时,您必须使用标签的“for”属性将其与输入相关联。 “for”属性的值应该是输入的“id”值。 (您已经包含了具有正确值的“for”属性。)

<input id="test_0" name="offering_cycle" type="checkbox" value="1">
<label for="test_0" class="">Fall</label>

(2) 阻止第一次点击事件的默认处理会阻止触发第二次点击事件,但这样做会破坏标签。也就是说,当点击标签时,复选框不会被选中/取消选中。

$('label[for*=test_]').on('click', function(event) {
    event.preventDefault();
    $(this).toggleClass('testing');
    // returning false would be another way to prevent the default handling.
});

jsfiddle


(3) 相反,您可以阻止第二个点击事件从输入中冒泡。

$('input:checkbox').on('click', function(event) {
    event.stopPropagation();
});

$('label[for*=test_]').on('click', function() {
    $(this).toggleClass('testing');
});

jsfiddle

注意:如果输入不是标签的子项,则没有必要。


(4) 或者您可以检查处理程序中的事件目标。它将是第一个点击事件的标签和第二个点击事件的输入。以下处理程序仅针对第一个点击事件执行 if 语句中的代码。

$('label[for*=test_]').on('click', function(event) {
    if (event.target == this) {
        $(this).toggleClass('testing');
    }
});

jsfiddle

注意:如果输入不是标签的子项,上面的代码仍然有效,但 if 语句将是不必要的,因为为输入触发的点击事件不会冒泡到标签。


改为处理输入的点击:

在您的情况下,您实际上不需要为标签元素注册点击处理程序。您可以改为为输入注册一个点击(或更改)处理程序。然后,您可以使用 $(this).closest('label') 获取标签元素。

$('input[name=offering_cycle]').on('click', function() {
     $(this).closest('label').toggleClass('testing');
});

jsfiddle

注意:如果输入不是标签的子项,当您点击标签时上面的处理程序仍会被调用,但是 $(this).closest('label') 会没有得到标签。您将不得不使用 $('label[for="' + this.id + '"]') 之类的东西。


关于标签元素上的“for”属性:

因为您在标签内有输入,所以没有必要在标签上包含 for 属性 --- 但它不是无效的。

您已将“for”属性值设置为输入元素的“id”属性值。这是使用“for”属性将标签与输入相关联的正确方法。如果您要包含具有无效值的“for”属性,则标签将不会与输入相关联,即使输入是标签的后代也是如此。

来自HTML5 spec对于标签元素的“for”属性:

The for attribute may be specified to indicate a form control with which the caption is to be associated. If the attribute is specified, the attribute's value must be the ID of a labelable element in the same Document as the label element. If the attribute is specified and there is an element in the Document whose ID is equal to the value of the for attribute, and the first such element is a labelable element, then that element is the label element's labeled control.

If the for attribute is not specified, but the label element has a labelable element descendant, then the first such descendant in tree order is the label element's labeled control.

关于javascript - 为什么在这个html/css/jquery中注册了两个点击事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30783660/

相关文章:

javascript - jQuery Slidetoggle - 仅在一个框上显示/隐藏子菜单

javascript - 使用粘性导航栏平滑滚动 Bootstrap 页面

javascript - 如何从范围对象中获取所需的数字位数?

javascript - 如何在没有 onclick 属性帮助的情况下在 jQuery 函数中传递值?

javascript - 如何将 onclick 事件添加到动态生成的按钮并显示/隐藏表格

jquery - 如何在angularjs中获取克隆的div数据

javascript - 在 JavaScript 中调用函数而不触发(头脚本是 jQuery 和 jQuery Mobile)

javascript - jQuery .html() 方法在 (document).ready 内部有效,但在外部无效

javascript - 防止 DIV 在 DOM 内容更改时滚动

javascript - 将 HTML Id 与对象的属性相匹配