2015-01-11 41 views
4

我想使用純Javascript將單個函數綁定到多個事件。是否有一種純Javascript方法將一個函數應用於多個元素的事件?

在jQuery中,我會用:

$('.className').click(function(e){ //do stuff }); 

因此,使用純JS我想:

document.getElementsByClassName('className').onclick = function(e){ //do stuff }; 

不工作,因爲getElementsByClassName返回一個數組,而不是一個DOM對象。

我可以通過數組循環,但這似乎過於冗長,就像它不應該是必要的:

var topBars = document.getElementsByClassName('className'); 
for(var i = 0; i < topBars.length; i++){ 
    topBars[i].onclick = function(e){ //do stuff }; 
} 

是否有使用純JavaScript來完成這個標準呢?

+1

不是,沒有。 –

+1

jQuery做了相同的循環....只有它在引擎蓋下才能做到這一點 – charlietfl

+1

這正是jQuery所做的。但是你可以使用'Array.map.call()'。但它不是真的更慢/更快。 – Mouser

回答

8

您可以在事件處理程序添加到父元素,然後確定是否與所需的類名兒童元素的一個點:

var parent = document.getElementById('parent'); 
parent.addEventListener('click', function (e) { 
    if ((' ' + e.target.className + ' ').indexOf(' item ') !== -1) { 
     // add logic here 
     console.log(e.target); 
    } 
}); 

Example Here

或...

var parent = document.getElementById('parent'); 
parent.addEventListener('click', function (e) { 
    Array.prototype.forEach.call(parent.querySelectorAll('.item'), function (el) { 
     if (el === e.target) { 
      // add logic here 
      console.log(e.target); 
     } 
    }); 
}); 

Example Here


上述代碼片段只有在您點擊具有指定類別的元素時纔會起作用。換句話說,如果你點擊給定元素的孩子,它將不起作用。要解決這一點,你可以使用以下命令:

var parent = document.getElementById('parent'); 
parent.addEventListener('click', function (e) { 
    var target = e.target; // Clicked element 
    while (target && target.parentNode !== parent) { 
     target = target.parentNode; // If the clicked element isn't a direct child 
     if (!target) { return; } // If element doesn't exist 
    } 
    if ((' ' + target.className + ' ').indexOf(' item ') !== -1){ 
     // add logic here 
     console.log(target); 
    } 
}); 

Alternative Example

var parent = document.getElementById('parent'); 

parent.addEventListener('click', function (e) { 
    var target = e.target; // Clicked element 
    while (target && target.parentNode !== parent) { 
     target = target.parentNode; // If the clicked element isn't a direct child 
     if (!target) { return; } // If element doesn't exist 
    } 
    Array.prototype.forEach.call(parent.querySelectorAll('.item'), function (el) { 
     if (el === target) { 
      // add logic here 
      console.log(target); 
     } 
    }); 
}); 

Example Here

+0

'e.target.className.indexOf('item')== = 0'應該是'e.target.className.indexOf('item')!== -1'我想。 –

+0

@JoshCrozier,我認爲它在第二個例子中變得非常複雜。它是正確的並且仍然只需要一個事件所以我仍然喜歡它:-) – Mouser

+1

儘管我認爲循環對於我當前的需求來說更好(也不太複雜),但我會選擇這個答案,因爲它似乎記錄了循環的最佳替代方法。 –

-1
var elems = document.querySelectorAll('.className'); 
var values = Array.prototype.map.call(elems, function(obj) { 
    return obj.onclick = function(e){ //do stuff }; 
}); 

這個(自MDN改編的例子)是你如何在沒有傳統循環的情況下做到這一點。

+2

1.它不比OP的代碼更好2.它實際上更差 – zerkms

+0

@zerkms。這不是更好。我在評論中說過。但你能解釋爲什麼它更糟嗎?這個例子可以在MDN上找到(這本身並不是一個好例子)。請賜教。 – Mouser

+2

'[class =「classname」]'---這個選擇器與問題中的選擇器不相同。另一個個人的事情是:'[] .map.call' ---我不想在不需要時創建對象:'Array.prototype.map.call'會做。 – zerkms

1

一劈,其中DOM使用原型繼承模型來實現(大多數瀏覽器,但不所有),您可以將一個迭代器添加到NodeList構造函數中:

if (NodeList && NodeList.prototype && !NodeList.prototype.forEach) { 
    NodeList.prototype.forEach = function(callback, thisArg) { 
    Array.prototype.forEach.call(this, callback, thisArg) 
    } 
} 

然後:

document.getElementsByClassName('item').forEach(function(el){ 
    el.addEventListener('click', someFn, false); 
}) 

document.querySelectorAll('.item').forEach(function(el){ 
    el.addEventListener('click', someFn, false); 
}) 

當然,你不應該這樣做在生產中在網絡上(don't mess with host objects和所有),但不會是好,如果它是確定?或者迭代器被添加到DOM列表和集合?

+0

1+不錯,我不知道這是可能的。 –

相關問題