2015-06-11 25 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'); 
});