ฉันจะรับเหตุการณ์คลิกภายใน innerHTML ได้อย่างไร


12

ฉันเค้าโครงนี้ที่สร้างขึ้นแบบไดนามิก:

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>

และฉันต้องการรับเหตุการณ์คลิกที่แต่ละh4 class="name"รายการและแสดงบันทึกพร้อมหมายเลขiที่เกี่ยวข้อง

อย่างไรก็ตามconsole.logจะแสดงเฉพาะที่iเกี่ยวข้องล่าสุด( i=9ในกรณีนี้) และไม่ทำงานกับiตัวเลขอื่น ๆ ทำไมสิ่งนี้ถึงเกิดขึ้น ฉันต้องทำอะไร?


3
อาจใช้Document.createElement ()แทนที่จะผ่าน html-string และคุณจะมีเวลาง่ายขึ้นมาก & ฉันคิดว่าคุณจะจบลงด้วยรหัสที่ดีขึ้นในตอนท้าย
admcfajn

1
คุณจะต้องวนซ้ำโหนดของคุณอีกครั้งและแนบกิจกรรมที่คุณไม่สามารถแนบเป็นสตริงได้
Eugen Sunic

คำถามที่ดีมันค่อนข้างยุ่งยากแน่นอนฉันคิดว่ามันอาจเป็นไปได้ที่จะเข้าร่วมการเรนเดอร์การโพสต์เหตุการณ์ .. ตัวอย่างเช่นหลังจากที่forลูปของคุณเรียกวิธีเพื่อใช้เหตุการณ์กับองค์ประกอบเหล่านั้น แต่ฉันไม่รู้ จะ jsFiddle เพื่อทดสอบ
Pogrindis

สร้างตัวจัดการเหตุการณ์ที่ได้รับมอบหมายสำหรับการ.card-bodyและตรวจสอบว่าองค์ประกอบ ( target) เป็นผู้ประกาศข่าวที่มีและ ID titleที่เริ่มต้นด้วย
Hungerstar

1
อาเพิ่งโพสต์คำตอบ โหวตให้เปิดใหม่ การปิดไม่จำเป็นปัญหาคือการinnerHTML += ...ฆ่าผู้ฟังเหตุการณ์ที่กำหนดไว้ก่อนหน้านี้ไม่ใช่การปิด ใช้document.createElementแทน ดูกระทู้นี้
ggorlen

คำตอบ:


8

innerHTMLวาด html แบบเต็มดังนั้นเหตุการณ์ที่แนบมาก่อนหน้านี้ทั้งหมดจะสูญหายไป ใช้insertAdjacentHTML()

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
ว้าว .. ฉันยุ่งกับสิ่งต่าง ๆ และไม่เคยมาครั้งinsertAdjacentHTML- ทุกวัน schoolday ดีจริงๆ
Pogrindis

1
เจ๋งมากและ +1 แต่ก็ยังมีราคาแพงและไม่จำเป็นต้องใช้document.getElementByIdทันทีหลังจากเพิ่ม HTML หากคุณกำลังเพิ่มองค์ประกอบหลายร้อยรายการนี่เป็นงานที่ต้องทำมากมาย
ggorlen

@ggorlen ฉันเห็นด้วยกับเรื่องที่น่าสนใจโดยการใช้คลาสnameและทำการจัดกิจกรรมให้กับคลาสนั้นในขณะที่ผ่านองค์ประกอบ
Pogrindis

1
ไม่แน่ใจ. ขึ้นอยู่กับการใช้งานจริง - ข้อเสนอแนะของฉันอาจเป็นการเพิ่มประสิทธิภาพก่อนวัยอันควร คุณจะต้องโปรไฟล์ / มาตรฐานและดู แต่ถ้าdocument.createElementสามารถใช้ได้ฉันคิดว่านั่นเป็นวิธีพื้นฐานที่ดีที่สุด การปรับปรุงที่เป็นไปได้อีกอย่างสำหรับโพสต์นี้คือการใช้สองลูป: อันแรกเพื่อสร้าง HTML ทั้งหมดจากนั้นอีกอันเพื่อคว้าองค์ประกอบทั้งหมดโดยใช้คลาสในการdocument.querySelectorAllโทรครั้งเดียวและเพิ่มผู้ฟังเหตุการณ์
ggorlen

1
แน่นอนว่ามันคุ้มค่ากับมาตรฐานฉันไม่สามารถคิดถึงสิ่งที่ดีกว่าที่จะทำในคืนนี้! :)
Pogrindis

8

ใช้+=ในการinnerHTMLทำลายผู้ฟังเหตุการณ์ในองค์ประกอบภายใน HTML document.createElementวิธีที่ถูกต้องในการทำเช่นนี้คือการใช้ นี่คือตัวอย่างเล็ก ๆ น้อย ๆ ที่สมบูรณ์:

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;
}

แน่นอนว่าdocument.getElementByIdไม่จำเป็นที่นี่เพราะเราเพิ่งสร้างวัตถุในบล็อกวน วิธีนี้ช่วยประหยัดต้นไม้ที่มีราคาแพง

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;
}

หากคุณมีชิ้นส่วนของ HTML แบบสตริงตามอำเภอใจตามตัวอย่างคุณสามารถใช้createElement("div")ตั้งค่าinnerHTMLหนึ่งครั้งเป็นชิ้นและเพิ่มผู้ฟังได้ตามต้องการ จากนั้นผนวก divs เป็นลูกขององค์ประกอบคอนเทนเนอร์ของคุณ

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
นี่คือวิธีการที่ฉันกำลังพิจารณาและฉันจะมอบวิธีการแก้ปัญหานี้ แต่คำตอบอื่น ๆ ก็ยอดเยี่ยมเช่นกัน
Pogrindis

ขอบคุณสำหรับคำตอบ แต่ฉันพยายามสร้างเลย์เอาต์ด้วย createElement และฉันไม่ประสบความสำเร็จ
Luiz Adorno

1
ไม่มีปัญหา. หวังว่าคุณตระหนักถึงถ้าคุณมีก้อนใหญ่ของ HTML คุณสามารถสร้างภาชนะองค์ประกอบรากเช่นนั้น<div> div.innerHTML += yourHugeChunkOfHTMLดังนั้นจึงไม่มีเหตุผลที่จะไม่สามารถใช้ได้กับทุกกรณี
ggorlen

1
ฉันจะพยายามสร้างเลย์เอาต์นี้ตามคำแนะนำของคุณฉันกลัวที่จะใช้ "document.getElementById" หลายครั้งและทำให้ประสิทธิภาพช้าลง
Luiz Adorno
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.