Làm cách nào tôi có thể nhận được sự kiện nhấp chuột bên trong InternalHTML?


12

Tôi đã bố trí này được tạo động:

for (let i = 1; i < 10; i++) {
  document.querySelector('.card-body').innerHTML += `<div class="row" id="img_div">
        <div class="col-12 col-sm-12 col-md-2 text-center">
          <img src="http://placehold.it/120x80" alt="prewiew" width="120" height="80">
        </div>
        <div id="text_div" class="col-12 text-sm-center col-sm-12 text-md-left col-md-6">
        <h4 class="name"><a href="#" id="title` + i + `">Name</a></h4>
          <h4>
            <small>state</small>
          </h4>
          <h4>
            <small>city</small>
          </h4>
          <h4>
            <small>zip</small>
          </h4>
        </div>
        <div class="col-12 col-sm-12 text-sm-center col-md-4 text-md-right row">
        </div>
      </div>
     `
  document.getElementById("title" + i).addEventListener('click', function() {
    console.log(i)
  });
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<div class="card-body">
  <!-- person -->
</div>

Và tôi muốn nhận được sự kiện nhấp vào từng sự kiện h4 class="name"và hiển thị một bản ghi với số iliên quan.

Tuy nhiên, console.logchỉ hiển thị các iliên quan cuối cùng ( i=9trong trường hợp này) và không hoạt động với các isố khác . Lý do tại sao điều này xảy ra? Tôi phải làm gì đây?


3
Có thể sử dụng Document.createEuity () thay vì chuyển chuỗi html & bạn sẽ có thời gian dễ dàng hơn nhiều và tôi nghĩ cuối cùng bạn sẽ có mã tốt hơn.
admcfajn

1
bạn sẽ phải lặp lại các nút của mình và đính kèm một sự kiện mà bạn không thể đính kèm vào một chuỗi
Eugen Sunic

Câu hỏi hay, chắc chắn là khá khó, tôi nghĩ có thể có thể kết xuất một kết xuất bài đăng sự kiện .. Ví dụ sau khi forvòng lặp của bạn gọi một phương thức để áp dụng các sự kiện cho các yếu tố đó, nhưng tôi không biết. sẽ jsFiddle để kiểm tra.
Pogrindis

Đã tạo một trình xử lý sự kiện được ủy nhiệm .card-bodyvà kiểm tra xem phần tử ( target) có phải là một neo với và ID bắt đầu bằng không title.
hungerstar

1
Ah, chỉ là để gửi một câu trả lời. Bình chọn để mở lại. Đóng cửa không cần thiết, vấn đề là innerHTML += ...giết chết người nghe sự kiện được thiết lập trước đó, không phải là đóng cửa. Sử dụng document.createElementthay thế. Xem chủ đề này
ggorlen

Câu trả lời:


8

innerHTMLvẽ lại html đầy đủ, kết quả là tất cả các sự kiện đính kèm trước đó bị mất. Sử dụnginsertAdjacentHTML()

for(let i=1;i<10;i++){
    document.querySelector('.card-body').insertAdjacentHTML('beforeend',`<div class="row" id="img_div">
        <div class="col-12 col-sm-12 col-md-2 text-center">
          <img src="http://placehold.it/120x80" alt="prewiew" width="120" height="80">
        </div>
        <div id="text_div" class="col-12 text-sm-center col-sm-12 text-md-left col-md-6">
        <h4 class="name"><a href="#" id="title`+i+`">Name</a></h4>
          <h4>
            <small>state</small>
          </h4>
          <h4>
            <small>city</small>
          </h4>
          <h4>
            <small>zip</small>
          </h4>
        </div>
        <div class="col-12 col-sm-12 text-sm-center col-md-4 text-md-right row">
        </div>
      </div>
     `);
   document.getElementById("title"+i).addEventListener('click', function () {
    console.log(i)
  });
}
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<div class="card-body">
<!-- person -->
</div>


3
Wow .. Tôi đã loay hoay với những thứ mô phỏng và chưa bao giờ gặp nhau insertAdjacentHTML- Mỗi ngày một ngày, thực sự tốt đẹp.
Pogrindis

1
Rất tuyệt vời và +1, nhưng nó vẫn có vẻ tốn kém và không cần thiết phải sử dụng document.getElementByIdngay sau khi thêm HTML. Nếu bạn thêm hàng trăm yếu tố, đây là rất nhiều công việc đi qua.
ggorlen

@ggorlen Tôi đồng ý về lĩnh vực hoàn hảo mà họ quan tâm sẽ sử dụng lớp namevà kết hợp sự kiện với lớp đó trong khi chuyển qua phần tử (hoặc có thể chỉ đọc từ chính sự kiện) sẽ hiệu quả hơn?
Pogrindis

1
Không chắc. Phụ thuộc vào việc sử dụng thực tế - đề xuất của tôi có thể là tối ưu hóa sớm. Bạn sẽ phải hồ sơ / điểm chuẩn và xem. Nhưng nếu document.createElementcó thể được sử dụng, tôi nghĩ đó thường là cách tiếp cận cơ bản tốt nhất. Một cải tiến có thể khác cho bài đăng này là sử dụng hai vòng lặp: một vòng để xây dựng tất cả HTML, sau đó là một vòng lặp để lấy tất cả các thành phần bằng cách sử dụng một lớp trong một document.querySelectorAllcuộc gọi và thêm trình lắng nghe sự kiện.
ggorlen

1
Chắc chắn giá trị điểm chuẩn, tôi không thể nghĩ ra bất cứ điều gì tốt hơn để làm tối nay! :)
Pogrindis

8

Sử dụng +=trêninnerHTML phá hủy trình lắng nghe sự kiện trên các thành phần bên trong HTML. Cách chính xác để làm điều này là sử dụng document.createElement. Đây là một ví dụ tối thiểu, đầy đủ:

for (let i = 1; i < 10; i++) {
  const anchor = document.createElement("a");
  document.body.appendChild(anchor);
  anchor.id = "title" + i;
  anchor.href= "#";
  anchor.textContent = "link " + i;
  document.getElementById("title" + i)
    .addEventListener("click", e => console.log(i));
}
a {
  margin-left: 0.3em;
}

Dĩ nhiên document.getElementById không cần thiết ở đây vì chúng ta chỉ tạo đối tượng trong khối vòng lặp. Điều này tiết kiệm đi bộ cây đắt tiền.

for (let i = 1; i < 10; i++) {
  const anchor = document.createElement("a");
  document.body.appendChild(anchor);    
  anchor.href= "#";
  anchor.textContent = "link " + i;
  anchor.addEventListener("click", e => console.log(i));
}
a {
  margin-left: 0.3em;
}

Nếu bạn có các đoạn HTML tùy ý như trong ví dụ của mình, bạn có thể sử dụng createElement("div"), đặt nóinnerHTML một lần cho đoạn này và thêm trình nghe khi cần. Sau đó nối các div như là phần tử con của phần tử container của bạn.

for (let i = 1; i < 10; i++) {
  const rawHTML = `<div><a href="#" id="link-${i}">link ${i}</a></div>`;
  const div = document.createElement("div");
  document.body.appendChild(div);
  div.href= "#";
  div.innerHTML = rawHTML;
  div.querySelector(`#link-${i}`)
    .addEventListener("click", e => console.log(i));
}


1
Đây là cách tiếp cận tôi đang xem xét và tôi sẽ đưa ra giải pháp này, nhưng câu trả lời khác cũng rất tuyệt.
Pogrindis

Cảm ơn vì đã trả lời, nhưng tôi đã cố gắng xây dựng bố cục với createdEuity và tôi đã không thành công
Luiz Adorno

1
Không vấn đề gì. Hy vọng rằng bạn nhận ra nếu bạn có một đoạn HTML lớn, bạn có thể tạo một thùng chứa phần tử gốc như một <div>, sau đó div.innerHTML += yourHugeChunkOfHTML. Vì vậy, không có lý do gì điều này không hoạt động cho bất kỳ trường hợp sử dụng.
ggorlen

1
Tôi sẽ cố gắng xây dựng bố cục này với đề xuất của bạn, tôi ngại sử dụng "document.getEuityById" nhiều lần và làm chậm hiệu suất
Luiz Adorno
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.