为什么在此html/css/jquery中注册了两个单击事件

smi*_*omb 8 html javascript css jquery javascript-events

我正在尝试设置复选框列表的样式.我添加了我的样式,它们在渲染时显示正确.我想在单击复选框的标签时添加一个类.这是我的标记,这在jsfiddle中是相同的.您可以从我的小提琴中看到,只需单击一下即可注册两个点击事件.为什么?

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>
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

jQuery的:

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

Joh*_*n S 5

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

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


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

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

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

<input id="test_0" name="offering_cycle" type="checkbox" value="1">
<label for="test_0" class="">Fall</label>
Run Code Online (Sandbox Code Playgroud)

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

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

提琴手


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

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

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

提琴手

注意:如果输入不是标签的子元素,则没有必要这样做。


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

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

提琴手

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


改为处理输入的点击:

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

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

提琴手

注意:如果输入不是标签的子元素,则在您单击标签时仍会调用上面的处理程序,但$(this).closest('label')不会获取标签。你将不得不使用类似的东西$('label[for="' + this.id + '"]')。


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

由于您在标签中有输入,因此没有必要for在标签上包含属性 --- 但它并非无效。

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

来自标签元素“for”属性的HTML5 规范:

可以指定 for 属性来指示与标题相关联的表单控件。如果指定了该属性,则该属性的值必须是与该标签元素位于同一文档中的可标签元素的 ID。如果指定了属性,并且文档中存在一个元素的 ID 等于 for 属性的值,并且第一个这样的元素是可标记元素,则该元素是标签元素的标记控件。

如果没有指定 for 属性,但是 label 元素有一个 labelable 元素后代,那么树顺序中的第一个这样的后代是 label 元素的标签控件。