JavaScript bấm trình nghe sự kiện trên lớp


220

Tôi hiện đang cố gắng viết một số JavaScript để có được thuộc tính của lớp đã được nhấp. Tôi biết rằng để làm điều này đúng cách, tôi nên sử dụng một người nghe sự kiện. Mã của tôi như sau:

var classname = document.getElementsByClassName("classname");

var myFunction = function() {
    var attribute = this.getAttribute("data-myattribute");
    alert(attribute);
};

classname.addEventListener('click', myFunction(), false);

Tôi đã mong đợi nhận được một hộp cảnh báo mỗi lần tôi nhấp vào một trong các lớp để cho tôi biết thuộc tính nhưng thật không may, nó không hoạt động. Ai có thể giúp tôi không?

( Lưu ý - Tôi có thể dễ dàng thực hiện việc này trong jQuerynhưng tôi KHÔNG muốn sử dụng nó )


2
Có một vấn đề với mã đó là thêm trình nghe sự kiện. addEventListener lấy tên sự kiện ('click'), tham chiếu đến hàm (không phải là kết quả của hàm như hiện tại bằng cách gọi myFactor () bằng parens) và cờ để biểu thị sự kiện sủi bọt. Cuộc gọi addEventListener sẽ trông giống như: elem.addEventListener ('click', myFunction, false) và classname là một loại NodeList. Cần lặp lại tất cả các yếu tố và gắn người nghe vào từng người trong danh sách.
Joey Guerra

Câu trả lời:


373

Điều này nên làm việc. getElementsByClassNametrả về một mảng đối tượng giống như mảng (xem chỉnh sửa) của các phần tử phù hợp với tiêu chí.

var elements = document.getElementsByClassName("classname");

var myFunction = function() {
    var attribute = this.getAttribute("data-myattribute");
    alert(attribute);
};

for (var i = 0; i < elements.length; i++) {
    elements[i].addEventListener('click', myFunction, false);
}

jQuery thực hiện phần lặp cho bạn, điều bạn cần làm trong JavaScript đơn giản.

Nếu bạn có hỗ trợ ES6, bạn có thể thay thế dòng cuối cùng của mình bằng:

    Array.from(elements).forEach(function(element) {
      element.addEventListener('click', myFunction);
    });

Lưu ý: Các trình duyệt cũ hơn (như IE6, IE7, IE8) không hỗ trợ getElementsByClassNamevà vì vậy chúng trở lại undefined.


EDIT: Sửa chữa

getElementsByClassNamekhông trả về một mảng, nhưng hầu hết HTMLCollection hoặc NodeList trong một số trình duyệt ( Mozilla ref ). Cả hai loại này đều giống như Array, (có nghĩa là chúng có thuộc tính độ dài và các đối tượng có thể được truy cập thông qua chỉ mục của chúng), nhưng không hoàn toàn là một Array hoặc được kế thừa từ một Array. (có nghĩa là các phương thức khác có thể được thực hiện trên Mảng không thể được thực hiện trên các loại này)

Cảm ơn người dùng @ Nemo đã chỉ ra điều này và giúp tôi khai thác để hiểu đầy đủ.


6
Điều này hoạt động hoàn hảo. Cảm ơn bạn. Tôi thực sự không nhận ra rằng jQuery đã lặp. Anudeep giúp đỡ rất nhiều. Dưới đây là câu trả lời làm việc của bạn: jsfiddle.net/LWda3/2
30secondstosam

2
document.getElementsByClassNamethực sự luôn trả về một mảng, ngay cả khi chỉ có một yếu tố phù hợp với tiêu chí
Guilherme Sehn

Cẩn thận mặc dù phần tử đầu tiên của mảng là tất cả các phần tử dom. Vì vậy, hãy bắt đầu vòng lặp của bạn với 1
Vishal Sakaria

11
stackoverflow.com/a/13258908/1333493 "document.getElementsByClassName không trả về một mảng. Nó trả về một danh sách nút được duyệt qua như một tệp XML."
Nemo

9
Array.from()có một tham số thứ hai là một hàm bản đồ để có thể viết phần trên (giả sử hỗ trợ es6) Array.from(classname, c => c.addEventListener('click', myFunction));.
Kilmazed

12

* Điều này đã được chỉnh sửa để cho phép trẻ em của lớp mục tiêu kích hoạt các sự kiện. Xem dưới cùng của câu trả lời để biết chi tiết. *

Một câu trả lời thay thế để thêm một người nghe sự kiện vào một lớp nơi các mục thường xuyên được thêm và xóa. Điều này được lấy cảm hứng từ onchức năng của jQuery nơi bạn có thể chuyển qua bộ chọn cho một phần tử con mà sự kiện đang lắng nghe.

var base = document.querySelector('#base'); // the container for the variable content
var selector = '.card'; // any css selector for children

base.addEventListener('click', function(event) {
  // find the closest parent of the event target that
  // matches the selector
  var closest = event.target.closest(selector);
  if (closest && base.contains(closest)) {
    // handle class event
  }
});

Câu đố: https://jsfiddle.net/u6oje7af/94/

Điều này sẽ lắng nghe các nhấp chuột vào basephần tử con của phần tử và nếu mục tiêu của một nhấp chuột có cha mẹ khớp với bộ chọn, sự kiện lớp sẽ được xử lý. Bạn có thể thêm và xóa các thành phần tùy thích mà không cần phải thêm nhiều người nghe nhấp chuột vào các thành phần riêng lẻ. Điều này sẽ nắm bắt tất cả chúng ngay cả đối với các phần tử được thêm vào sau khi trình nghe này được thêm vào, giống như chức năng của jQuery (mà tôi tưởng tượng là hơi giống nhau dưới mui xe).

Điều này phụ thuộc vào sự kiện lan truyền, vì vậy nếu bạn stopPropagationvào sự kiện ở nơi khác, điều này có thể không hoạt động. Ngoài ra, closestchức năng có một số vấn đề tương thích với IE rõ ràng (những gì không?).

Điều này có thể được thực hiện thành một chức năng nếu bạn cần thực hiện loại hành động này nghe nhiều lần, như

function addChildEventListener(base, eventName, selector, handler) {
  base.addEventListener(eventName, function(event) {
    var closest = event.target.closest(selector);
    if (closest && base.contains(closest)) {
      // passes the event to the handler and sets `this`
      // in the handler as the closest parent matching the
      // selector from the target element of the event
      handler.call(closest, event);
    }
  });
}

=========================================
EDIT: Bài đăng này ban đầu sử dụng matcheschức năng cho Các phần tử DOM trên mục tiêu sự kiện, nhưng điều này đã giới hạn các mục tiêu của sự kiện chỉ cho lớp trực tiếp. Nó đã được cập nhật để sử dụng closestchức năng thay thế, cho phép các sự kiện trên trẻ em của lớp mong muốn cũng kích hoạt các sự kiện. matchesMã ban đầu có thể được tìm thấy tại fiddle gốc: https://jsfiddle.net/u6oje7af/23/


3

Bạn có thể sử dụng mã dưới đây:

document.body.addEventListener('click', function (evt) {
    if (evt.target.className === 'databox') {
        alert(this)
    }
}, false);

Tôi sẽ phải thử, đây là một cách tiếp cận độc đáo mà thực sự có thể dễ dàng hơn để duy trì và thực hiện tốt hơn so với việc lặp!
Cliff Helsel

4
nếu phần tử có nhiều lớp, bạn sẽ phải kiểm tra giá trị chính xác trong các trường đó, vd. các lớp học và trật tự. tôi muốn đi choevt.target.classList.contains('databox')
honk31

8
Điều này có vẻ cực kỳ không hiệu quả với tôi. Mỗi sự kiện trên cơ thể sẽ đi qua chức năng này. Điều gì quá khó để duy trì về một vòng lặp?
JosefAssad

Điều này rất không hiệu quả, bạn sẽ đi qua từng yếu tố như @JosefAssad nói.
nullwriter

3

Với JavaScript hiện đại, nó có thể được thực hiện như thế này:

const divs = document.querySelectorAll('.a');

divs.forEach(el => el.addEventListener('click', event => {
  console.log(event.target.classList[1]);
}));
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>Example</title>
  <style>
    .a {
      background-color:red;
      height: 33px;
      display: flex;
      align-items: center;
      margin-bottom: 10px;
      cursor: pointer;
    }
    
    .b {
      background-color:#00AA00;
      height: 50px;
      display: flex;
      align-items: center;
      margin-bottom: 10px;
    }
  </style>
</head>
<body>
  <div class="a a-1">1</div>
  <div class="b">2</div>
  <div class="a a-2">11</div>
</body>
</html>

  1. Nhận tất cả các yếu tố theo tên lớp
  2. Vòng lặp trên tất cả các yếu tố với việc sử dụng forEach
  3. Đính kèm một người nghe sự kiện trên mỗi yếu tố
  4. Sử dụng event.targetđể lấy thêm thông tin cho phần tử cụ thể
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.