2015-06-11 28 views
7

中注册两个点击事件我正在尝试设置复选框列表的样式。我已经添加了我的样式,并且它们在呈现时正确显示。我想在复选框的标签被点击时添加一个类。这是我的标记和here is the same in a jsfiddle。您可以从我的小提琴中看到,只需点击一次即可注册两个点击事件。为什么?为什么在这个html/css/jquery

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

您将单击事件绑定到标签,但如果有人单击标签内的某个元素,它可能会创建两个点击事件。一个用于子元素,另一个用于父元素。 –

+0

@b_dubb正是我的想法。我相信它也会为输入生成一个点击事件! – Michelangelo

+0

您可以从标签中取出输入。看起来控件看起来是一样的,你不会有这个问题 –

回答

1

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

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


如果你真的想处理的标签click事件(并有它的点击只执行一次):

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

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

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

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

$('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)相反,你可以从输入冒泡停止第二click事件。

$('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”属性值设置为输入元素的“id”属性的值。这是使用“for”属性将标签与输入相关联的正确方法。如果要包含具有无效值的“for”属性,即使输入是标签的后代,标签也不会与输入关联。

HTML5 spec为的“for”的标签元件的属性:

for属性可被指定为指示与 表单控件,其标题是要关联。如果指定了属性,则该属性的值必须是与标签元素相同的文档中的一个可插入元素的ID。如果指定了属性,并且 在Document中有一个元素的ID等于值 for属性,并且第一个这样的元素是可标记元素 那么该元素是标签元素的标签控件。

如果未指定for属性,但标签元素具有可描述元素后代,则树 顺序中的第一个这样的后代是标签元素的标记控制。

2

您也可以尝试:

$('label[for^="test_"]').click(function(){ 
    $('div#target').append($(this).clone()); 
    return false;  
}); 
+0

其实应该使用这个:https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault –

+0

我们已经想通了问题是事件传播两次。返回'false'会停止这个操作,而且非常简洁,这让我很喜欢这个答案。我只是好奇,如果稍后回顾一下这个代码时,更详细的答案会更好,我可能不明白为什么我这样做。使用'stopPropagation()'似乎更友好。 – smilebomb

+0

@ RokoC.Buljan'preventDefault()'会停止检查输入吗? – smilebomb

0

对于属性在给定标签上应该链接到名称的输入不是ID

您可以在事件上调用方法stopPropagation,并且可以将事件注入到点击处理程序中。

例子:

$('label[for*=test_]').on('click',function(e){ 
    e.stopPropagation(); 
}); 

HTML示例:

<div class="parent something"> 
    <div class="child something"> 
    </div> 
</div> 

现在,如果你有一个点击处理程序上div.something它不会解雇两次,但你仍然可以同时使用。

来源:

+0

当我在jsfiddle中进行更改时,这不起作用。停止传播的想法是正确的,但是这个标记不起作用。 http://jsfiddle.net/fdm1pmj2/18/ – smilebomb

+0

修复http://jsfiddle.net/c0xuhpy8/ –

+1

从[HTML5规范](http://www.w3.org/TR/html5/forms.html# attr-label-for)作为标签元素的“for”属性:“如果指定了属性,则该属性的值必须是与label元素相同的Document中的一个可插入元素的ID。“通过给”for“属性赋一个无效值,你就解除了与输入的关联,这就是为什么它只能在你的小提琴中获得一个点击事件,它不再导致输入被选中/取消选中[jsfiddle] (http://jsfiddle.net/patv6p8y/1/) –

0

好了,所以我在评论说。它生成两个click事件,做到这一点,而不是和它的作品就像一个魅力:Fiddle

$('input').on('click',function(){ 
    console.log("clicked"); 
    $('div#target').append($(this).parent().clone());  
}); 

您可能要重命名的输入。

0

反而试试这个。

为所有Label和Fire事件添加一个公共类。 像这样:

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

而且比,

$(".testClass").on('click',function(){ 
     $(this).toggleClass('testing'); 
}); 
1

那是因为你在label包含checkbox结合事件,您正在使用for="chekbox_id"。因此,该事件被激发为label以及checkbox

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

label中取出input

演示:http://jsfiddle.net/tusharj/fdm1pmj2/5/

+0

@ RokoC.Buljan这就是我刚才的想法,改变标记不是一种选择,你认为返回'false'就像bitsm建议是一个很好的解决方案吗? – smilebomb

+0

解决方法是不要输入标签 –

+0

@jefffabiny实际上你应该使用'event.preventDefault()' - 查看我的答案获得更多细节 –

0

的点击事件被触发两次:一次是为标签,另一次的复选框。您只需选择复选框。

$('label[for*=test_] > input').on('click',function(){ 
    $('div#target').append($(this).parent().clone());  
}); 

JSFiddle here

0

为了解释发生了什么:

  • 输入点击,但由于标签被绑定到使用for属性,它的输入和简单是它的子元素,这里是你的第一次注册事件。
  • 比输入传播的点击(所有元素传播点击)下降到标签,因为标签是你的委托元素 - 这里是触发你的第二个事件。

既然你包你输入一个复选框LABEL元素中,
实际上你可以收听在连上input

$('label[for*=test_] input').on('click',function(){ 
    $('div#target').append($(this).closest("label").clone());  
}); 

,比克隆父标签。 jsFiddle


的另一种方式,以防止标签和内部输入端之间的兄弟情谊是停止输入来传播事件让边界标签>>复选框,它的工作:fiddle

$("label:input").on("click", function(evt) { 
    evt.stopPropagation(); 
}); 
$('label[for*=test_]').on('click',function(){ 
    $('div#target').append($(this).clone()); 
}); 

否则你可能防止默认标签的行为jsFiddle
从绑定的输入触发回事件和目前正使用e.preventDefault()但你的(隐藏)输入复选框不会得到遏制!

$('label[for*=test_]').on('click',function(e){ 
    e.preventDefault(); 
    $('div#target').append($(this).clone()); 
}); 

https://developer.mozilla.org/en-US/docs/Web/API/Event/preventDefault

+0

由于某种原因,我无法得到这个工作,我正在尝试使用'stopPropagation()'示例,我需要切换类而不是克隆一个元素。出于说明目的进行了克隆。当我将行更改为'toggleClass()'而不是'clone()'时,您可以看到该类永远不会被添加。 http://jsfiddle.net/rq6y4sw6/4/ – smilebomb

+0

@jefffabiny这是导致输入,它的标签文本(标签由LABEL)是第一个注册事件,并且由于事件停止 - 标签不能改变类!得到它了? :)如果你只考虑我的第一个例子...这是一个演示:http://jsfiddle.net/rq6y4sw6/6/ –

0

你可以试试这个...

$("label").find("*").click(function(event) { 
    event.stopPropagation(); 
}); 

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