การมอบหมายกิจกรรม DOM คืออะไร


202

ทุกคนสามารถอธิบายการมอบหมายเหตุการณ์ใน JavaScript ได้หรือไม่และมีประโยชน์อย่างไร


2
มันจะดีถ้ามีลิงก์ไปยังแหล่งข้อมูลที่เป็นประโยชน์เกี่ยวกับเรื่องนี้ 6 ชั่วโมงในนี้เป็น google hit สูงสุดสำหรับ "ตัวแทนเหตุการณ์ dom" อาจเป็นลิงค์ที่มีประโยชน์หรือไม่ ฉันไม่แน่ใจว่าทั้งหมด: w3.org/TR/DOM-Level-2-Events/events.html
ฌอน McMillan

หรืออาจเป็นเช่นนี้: sitepoint.com/blogs/2008/07/23/…
Sean McMillan

7
นี่คือหนึ่งที่นิยม แม้แต่ fb guys ลิงก์มายังสิ่งนี้สำหรับหน้า reactjs ของพวกเขาdavidwalsh.name/event-delegate
Sorter

ดูjavascript.info/event-delegationนี้จะช่วยคุณได้มาก
Suraj Jain

คำตอบ:


330

การมอบหมายเหตุการณ์ DOM เป็นกลไกในการตอบสนองต่อเหตุการณ์ UI ผ่านผู้ปกครองทั่วไปเดียวมากกว่าเด็กแต่ละคนผ่านความมหัศจรรย์ของเหตุการณ์ "เดือดปุด ๆ " (การเผยแพร่เหตุการณ์ aka)

เมื่อมีการเรียกใช้เหตุการณ์ในองค์ประกอบรายการต่อไปนี้จะเกิดขึ้น :

เหตุการณ์ถูกส่งไปยังเป้าหมาย EventTargetและผู้ฟังกิจกรรมใด ๆ ที่พบว่ามีการเปิดใช้งาน จากนั้นเหตุการณ์Bubblingจะทริกเกอร์ผู้ฟังเหตุการณ์เพิ่มเติมที่พบโดยติดตามEventTargetห่วงโซ่ผู้ปกครองขึ้นด้านบนตรวจสอบผู้ฟังเหตุการณ์ที่ลงทะเบียนในแต่ละ EventTarget ที่ต่อเนื่องกัน Documentการขยายพันธุ์นี้ขึ้นจะยังคงขึ้นไปถึงและรวมทั้ง

การจัดอีเวนท์เป็นพื้นฐานสำหรับการมอบหมายอีเวนต์ในเบราว์เซอร์ ตอนนี้คุณสามารถผูกตัวจัดการเหตุการณ์กับองค์ประกอบพาเรนต์เดียวและตัวจัดการนั้นจะถูกดำเนินการเมื่อใดก็ตามที่เหตุการณ์เกิดขึ้นบนโหนดลูกใด ๆ (และลูก ๆ ของพวกเขา) นี่คือการมอบหมายกิจกรรม นี่คือตัวอย่างของมันในทางปฏิบัติ:

<ul onclick="alert(event.type + '!')">
    <li>One</li>
    <li>Two</li>
    <li>Three</li>
</ul>

ด้วยตัวอย่างนั้นถ้าคุณต้องคลิกที่<li>โหนดลูกใด ๆคุณจะเห็นการแจ้งเตือน"click!"ถึงแม้ว่าจะไม่มีตัวจัดการการคลิกที่ถูกผูกไว้กับที่<li>คุณคลิก หากเราผูกพันคุณonclick="..."แต่ละคน<li>จะได้รับผลกระทบที่เหมือนกัน

แล้วประโยชน์คืออะไร

ลองนึกภาพตอนนี้คุณจำเป็นต้องเพิ่ม<li>รายการใหม่ไปยังรายการด้านบนผ่านการจัดการ DOM:

var newLi = document.createElement('li');
newLi.innerHTML = 'Four';
myUL.appendChild(newLi);

โดยไม่ต้องใช้การมอบหมายเหตุการณ์คุณจะต้อง "rebind" "onclick"ตัวจัดการเหตุการณ์ไปยัง<li>องค์ประกอบใหม่เพื่อให้มันทำหน้าที่เช่นเดียวกับพี่น้อง ด้วยการมอบหมายกิจกรรมคุณไม่จำเป็นต้องทำอะไร เพียงเพิ่มใหม่<li>ลงในรายการและคุณทำเสร็จแล้ว

สิ่งนี้ยอดเยี่ยมมากสำหรับเว็บแอปที่มีตัวจัดการเหตุการณ์เชื่อมโยงกับองค์ประกอบหลายอย่างซึ่งองค์ประกอบใหม่จะถูกสร้างขึ้นและ / หรือลบออกใน DOM ด้วยการมอบหมายเหตุการณ์จำนวนของการผูกเหตุการณ์สามารถลดลงอย่างมากโดยการย้ายพวกเขาไปยังองค์ประกอบหลักทั่วไปและรหัสที่สร้างองค์ประกอบใหม่แบบไดนามิกได้ทันทีสามารถแยกออกจากตรรกะของการเชื่อมโยงตัวจัดการเหตุการณ์ของพวกเขา

ประโยชน์อีกประการหนึ่งสำหรับการมอบหมายเหตุการณ์คือการลดจำนวนหน่วยความจำทั้งหมดที่ใช้โดยตัวรับฟังเหตุการณ์ลดลง (เนื่องจากจำนวนการเชื่อมโยงเหตุการณ์ลดลง) มันอาจไม่ได้สร้างความแตกต่างมากนักสำหรับหน้าเล็ก ๆ ที่ขนถ่ายบ่อยครั้ง (เช่นผู้ใช้ไปยังหน้าต่าง ๆ บ่อยครั้ง) แต่สำหรับแอปพลิเคชันที่มีอายุการใช้งานยาวนานอาจมีความสำคัญ มีบางสถานการณ์ที่ยากต่อการติดตามเมื่อองค์ประกอบถูกลบออกจาก DOM ยังคงเรียกร้องหน่วยความจำ (เช่นพวกเขารั่วไหล) และบ่อยครั้งที่หน่วยความจำรั่วนี้ถูกผูกไว้กับเหตุการณ์ที่มีผลผูกพัน ด้วยการมอบหมายกิจกรรมคุณมีอิสระที่จะทำลายองค์ประกอบของเด็ก ๆ โดยไม่เสี่ยงที่จะลืม "แยก" ผู้ฟังเหตุการณ์ของพวกเขา (เนื่องจากผู้ฟังอยู่ที่บรรพบุรุษ) การรั่วไหลของหน่วยความจำประเภทนี้สามารถถูกเก็บไว้ได้ (ถ้าไม่ถูกกำจัดซึ่งยากที่จะทำในบางครั้ง IE กำลังมองหาคุณอยู่)

นี่คือตัวอย่างโค้ดที่ดีกว่าของการมอบหมายเหตุการณ์:


ฉันได้รับอนุญาตให้เข้าถึงเมื่อเปิดลิงก์ที่สามของคุณการมอบหมายกิจกรรมโดยไม่มีห้องสมุด javascript และ +1 สำหรับลิงก์สุดท้ายของคุณ
bugwheels94

สวัสดีขอขอบคุณสำหรับคำอธิบายที่ดี ฉันยังคงสับสนเกี่ยวกับรายละเอียดบางอย่าง แต่: วิธีที่ฉันเข้าใจการไหลของเหตุการณ์ DOM tree (ดังที่เห็นได้ใน3.1 การกระจายเหตุการณ์และการไหลของเหตุการณ์ DOM ) วัตถุเหตุการณ์แพร่กระจายจนกว่าจะถึงองค์ประกอบเป้าหมายจากนั้นฟองสบู่ขึ้น ทำไมมันถึงองค์ประกอบลูกของโหนดถ้าพาเรนต์ของโหนดนี้เป็นเป้าหมายของเหตุการณ์ เช่นเหตุการณ์จะเผยแพร่ไปยังเหตุการณ์ที่<li>ควรหยุดได้<ul>อย่างไร หากคำถามของฉันยังไม่ชัดเจนหรือต้องการเธรดแยกต่างหากฉันยินดีที่จะบังคับ
Aetos

@Aetos: > ทำไมมันถึงองค์ประกอบลูกของโหนดถ้าผู้ปกครองของโหนดนี้เป็นเป้าหมายเหตุการณ์ในคำถาม? มันไม่เป็นอย่างที่ฉันเข้าใจ เหตุการณ์เสร็จสิ้นขั้นตอนที่ 1 (การจับภาพ) ที่พาเรนต์ของเป้าหมายเข้าสู่เฟส 2 (เป้าหมาย) บนตัวเป้าหมายจากนั้นเข้าสู่เฟส 3 (การเดือดปุด ๆ ) เริ่มต้นที่พาเรนต์ของเป้าหมาย ไม่มีที่ไหนเลยที่จะเข้าถึงกลุ่มเป้าหมายได้
Crescent Fresh

@Crescent Fresh well แล้วเหตุการณ์จะมีผลกับโหนดลูกอย่างไรถ้ามันไม่เคยไปถึงมัน?
Aetos

1
คำตอบที่ยอดเยี่ยมจริงๆ ขอบคุณสำหรับการอธิบายการมอบหมายเหตุการณ์ด้วยข้อเท็จจริงที่เกี่ยวข้อง ขอบคุณ!
Kshitij Tiwari

30

การมอบหมายกิจกรรมช่วยให้คุณหลีกเลี่ยงการเพิ่มตัวรับฟังเหตุการณ์ในโหนดที่ระบุ ผู้ฟังเหตุการณ์จะถูกเพิ่มเข้าไปในพาเรนต์เดียว ผู้ฟังเหตุการณ์นั้นจะวิเคราะห์เหตุการณ์ที่เกิดขึ้นเพื่อค้นหารายการที่ตรงกันในองค์ประกอบย่อย

ตัวอย่าง JavaScript:

สมมติว่าเรามีองค์ประกอบ UL หลักที่มีองค์ประกอบย่อยหลายประการ:

<ul id="parent-list">
<li id="post-1">Item 1</li>
<li id="post-2">Item 2</li>
<li id="post-3">Item 3</li>
<li id="post-4">Item 4</li>
<li id="post-5">Item 5</li>
<li id="post-6">Item 6</li>

สมมติว่ามีบางสิ่งที่จำเป็นต้องเกิดขึ้นเมื่อองค์ประกอบลูกแต่ละอันถูกคลิก คุณสามารถเพิ่มผู้ฟังเหตุการณ์แยกกันในแต่ละองค์ประกอบ LI แต่จะเกิดอะไรขึ้นถ้าองค์ประกอบ LI ถูกเพิ่มและลบออกจากรายการบ่อยครั้ง การเพิ่มและลบผู้ฟังเหตุการณ์จะเป็นฝันร้ายโดยเฉพาะอย่างยิ่งหากการเพิ่มและลบรหัสอยู่ในสถานที่ต่าง ๆ ภายในแอปของคุณ ทางออกที่ดีกว่าคือการเพิ่มฟังเหตุการณ์ไปยังองค์ประกอบ UL หลัก แต่ถ้าคุณเพิ่มฟังเหตุการณ์ไปที่ผู้ปกครองคุณจะรู้ได้อย่างไรว่าองค์ประกอบใดถูกคลิก

ง่าย: เมื่อเหตุการณ์เกิดฟองอากาศจนถึงองค์ประกอบ UL คุณตรวจสอบคุณสมบัติเป้าหมายของวัตถุเหตุการณ์เพื่อรับการอ้างอิงไปยังโหนดที่คลิกจริง นี่คือตัวอย่าง JavaScript พื้นฐานที่แสดงการมอบหมายเหตุการณ์:

// Get the element, add a click listener...
document.getElementById("parent-list").addEventListener("click", function(e) {
// e.target is the clicked element!
// If it was a list item
if(e.target && e.target.nodeName == "LI") {
    // List item found!  Output the ID!
    console.log("List item ", e.target.id.replace("post-"), " was clicked!");
       }
 });

เริ่มต้นด้วยการเพิ่มฟังเหตุการณ์คลิกเพื่อองค์ประกอบหลัก เมื่อผู้เรียกเหตุการณ์ถูกเรียกใช้ให้ตรวจสอบองค์ประกอบเหตุการณ์เพื่อให้แน่ใจว่าเป็นประเภทขององค์ประกอบที่จะตอบสนอง ถ้ามันเป็นองค์ประกอบ LI บูม: เรามีสิ่งที่เราต้องการ! หากไม่ใช่องค์ประกอบที่เราต้องการเหตุการณ์ก็สามารถถูกละเว้นได้ ตัวอย่างนี้ค่อนข้างง่าย - UL และ LI เป็นการเปรียบเทียบแบบตรงไปตรงมา ลองทำอะไรที่ยากขึ้น มามี DIV พาเรนต์กับลูก ๆ หลาย ๆ คน แต่สิ่งที่เราใส่ใจคือแท็ก A พร้อมคลาส classA CSS

  // Get the parent DIV, add click listener...
  document.getElementById("myDiv").addEventListener("click",function(e) {
// e.target was the clicked element
if(e.target && e.target.nodeName == "A") {
    // Get the CSS classes
    var classes = e.target.className.split(" ");
    // Search for the CSS class!
    if(classes) {
        // For every CSS class the element has...
        for(var x = 0; x < classes.length; x++) {
            // If it has the CSS class we want...
            if(classes[x] == "classA") {
                // Bingo!
                console.log("Anchor element clicked!");
                // Now do something here....
            }
        }
    }

  }
});

http://davidwalsh.name/event-delegate


1
tweak ที่แนะนำ: ใช้ e.classList.contain () แทนในตัวอย่างสุดท้าย: developer.mozilla.org/en-US/docs/Web/API/Element/classList
nc

7

การมอบหมายเหตุการณ์โดมเป็นสิ่งที่แตกต่างจากคำนิยามของวิทยาศาสตร์คอมพิวเตอร์

มันหมายถึงการจัดการเหตุการณ์เดือดดาลจากองค์ประกอบหลายอย่างเช่นเซลล์ตารางจากวัตถุแม่เช่นตาราง มันสามารถทำให้โค้ดง่ายขึ้นโดยเฉพาะเมื่อเพิ่มหรือลบองค์ประกอบและบันทึกหน่วยความจำบางส่วน


6

คณะผู้แทนเป็นเทคนิคที่วัตถุแสดงพฤติกรรมบางอย่างไปสู่ภายนอก แต่ในความเป็นจริงได้มอบหมายความรับผิดชอบในการใช้พฤติกรรมนั้นไปยังวัตถุที่เกี่ยวข้อง เสียงนี้ในตอนแรกคล้ายกับรูปแบบพร็อกซี แต่มีจุดประสงค์ที่แตกต่างกันมาก การมอบหมายเป็นกลไกที่เป็นนามธรรมซึ่งรวบรวมพฤติกรรมของวัตถุ (เมธอด)

พูดโดยทั่วไป: ใช้การมอบหมายเป็นทางเลือกในการสืบทอด การสืบทอดเป็นกลยุทธ์ที่ดีเมื่อมีความสัมพันธ์ใกล้ชิดระหว่างวัตถุพ่อแม่และลูกอย่างไรก็ตามมรดกคู่วัตถุใกล้ชิดมาก บ่อยครั้งที่การมอบหมายเป็นวิธีที่ยืดหยุ่นกว่าในการแสดงความสัมพันธ์ระหว่างชั้นเรียน

รูปแบบนี้เรียกว่า "พร็อกซีเชน" รูปแบบการออกแบบอื่น ๆ อีกมากมายใช้การมอบหมาย - รัฐรูปแบบกลยุทธ์และผู้เข้าชมขึ้นอยู่กับมัน


คำอธิบายที่ดี ในตัวอย่างของ <ul> ที่มีเด็ก ๆ <li> หลายคนเห็นได้ชัดว่า <li> นั้นเป็นคนที่จัดการกับตรรกะการคลิก แต่มันไม่เป็นเช่นนั้นเพราะพวกเขา "มอบหมาย" ตรรกะนี้ในบิดา <ul>
Juanma Menendez

6

แนวคิดการมอบหมายงาน

หากมีองค์ประกอบหลายอย่างในหนึ่งพาเรนต์และคุณต้องการจัดการเหตุการณ์ที่เกิดขึ้นกับมัน - อย่าผูกตัวจัดการกับแต่ละองค์ประกอบ ให้ผูกตัวจัดการเดียวกับพาเรนต์และรับลูกจาก event.target ไซต์นี้ให้ข้อมูลที่เป็นประโยชน์เกี่ยวกับวิธีใช้การมอบหมายเหตุการณ์ http://javascript.info/tutorial/event-delegation


6

การมอบหมายกิจกรรมกำลังจัดการกับเหตุการณ์ที่ทำให้เกิดฟองโดยใช้ตัวจัดการเหตุการณ์บนองค์ประกอบคอนเทนเนอร์ แต่จะเปิดใช้งานพฤติกรรมของตัวจัดการเหตุการณ์เท่านั้นหากเหตุการณ์เกิดขึ้นบนองค์ประกอบภายในคอนเทนเนอร์ที่ตรงกับเงื่อนไขที่กำหนด สิ่งนี้สามารถทำให้การจัดการเหตุการณ์บนองค์ประกอบภายในคอนเทนเนอร์ง่ายขึ้น

ตัวอย่างเช่นสมมติว่าคุณต้องการจัดการการคลิกในเซลล์ตารางใด ๆ ในตารางขนาดใหญ่ คุณทำได้เขียนลูปเพื่อเชื่อมต่อตัวจัดการคลิกไปยังแต่ละเซลล์ ... หรือคุณสามารถเชื่อมโยงตัวจัดการคลิกบนตารางและใช้การมอบหมายเหตุการณ์เพื่อเรียกใช้เฉพาะเซลล์ตารางเท่านั้น (และไม่ใช่ส่วนหัวของตารางหรือช่องว่างภายใน แถวรอบเซลล์ ฯลฯ )

นอกจากนี้ยังมีประโยชน์เมื่อคุณจะเพิ่มและลบองค์ประกอบออกจากคอนเทนเนอร์เนื่องจากคุณไม่ต้องกังวลกับการเพิ่มและลบตัวจัดการเหตุการณ์ในองค์ประกอบเหล่านั้น เพียงแค่เกี่ยวเหตุการณ์บนภาชนะและจัดการเหตุการณ์เมื่อมันฟอง

ต่อไปนี้เป็นตัวอย่างง่ายๆ (โดยเจตนาจะให้คำอธิบายแบบอินไลน์): การจัดการการคลิกที่tdองค์ประกอบใด ๆในตารางคอนเทนเนอร์:

// Handle the event on the container
document.getElementById("container").addEventListener("click", function(event) {
    // Find out if the event targeted or bubbled through a `td` en route to this container element
    var element = event.target;
    var target;
    while (element && !target) {
        if (element.matches("td")) {
            // Found a `td` within the container!
            target = element;
        } else {
            // Not found
            if (element === this) {
                // We've reached the container, stop
                element = null;
            } else {
                // Go to the next parent in the ancestry
                element = element.parentNode;
            }
        }
    }
    if (target) {
        console.log("You clicked a td: " + target.textContent);
    } else {
        console.log("That wasn't a td in the container table");
    }
});
table {
    border-collapse: collapse;
    border: 1px solid #ddd;
}
th, td {
    padding: 4px;
    border: 1px solid #ddd;
    font-weight: normal;
}
th.rowheader {
    text-align: left;
}
td {
    cursor: pointer;
}
<table id="container">
    <thead>
        <tr>
            <th>Language</th>
            <th>1</th>
            <th>2</th>
            <th>3</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <th class="rowheader">English</th>
            <td>one</td>
            <td>two</td>
            <td>three</td>
        </tr>
        <tr>
            <th class="rowheader">Español</th>
            <td>uno</td>
            <td>dos</td>
            <td>tres</td>
        </tr>
        <tr>
            <th class="rowheader">Italiano</th>
            <td>uno</td>
            <td>due</td>
            <td>tre</td>
        </tr>
    </tbody>
</table>

ก่อนที่จะเข้าไปดูรายละเอียดของสิ่งนั้นขอเตือนตัวเองว่ากิจกรรม DOM ทำงานอย่างไร

เหตุการณ์ DOM ถูกส่งจากเอกสารไปยังองค์ประกอบเป้าหมาย ( เฟสการจับภาพ ) จากนั้นต่อมน้ำจากองค์ประกอบเป้าหมายกลับไปที่เอกสาร ( เฟสการทำให้เป็นฟอง ) กราฟิกนี้ในข้อมูลจำเพาะเหตุการณ์ DOM3เก่า(ตอนนี้ถูกแทนที่แล้ว แต่กราฟิกยังคงใช้ได้) แสดงได้ดี:

ป้อนคำอธิบายรูปภาพที่นี่

ไม่ทุกเหตุการณ์ฟอง clickแต่ส่วนใหญ่ทำรวมทั้ง

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

รหัสนั้นเขียนขึ้นเพื่อเรียกใช้แต่ละขั้นตอนอย่างละเอียด แต่ในเบราว์เซอร์ที่ทันสมัย ​​(และใน IE หากคุณใช้ polyfill) คุณสามารถใช้closestและcontainsแทนที่จะวนซ้ำ:

var target = event.target.closest("td");
    console.log("You clicked a td: " + target.textContent);
} else {
    console.log("That wasn't a td in the container table");
}

ตัวอย่างสด:

closestตรวจสอบองค์ประกอบที่คุณเรียกใช้เพื่อดูว่าตรงกับตัวเลือก CSS ที่กำหนดหรือไม่และส่งคืนองค์ประกอบเดียวกันนั้นหรือไม่ ถ้าไม่มันจะตรวจสอบองค์ประกอบหลักเพื่อดูว่ามันตรงกันและส่งกลับผู้ปกครองถ้าใช่; ถ้าไม่มันจะตรวจสอบผู้ปกครองของผู้ปกครอง ฯลฯ ดังนั้นจึงพบองค์ประกอบ "ใกล้ที่สุด" ในรายการบรรพบุรุษที่ตรงกับตัวเลือก เนื่องจากอาจผ่านองค์ประกอบคอนเทนเนอร์รหัสด้านบนใช้containsเพื่อตรวจสอบว่าพบองค์ประกอบที่ตรงกันหรือไม่มันอยู่ในคอนเทนเนอร์ - เนื่องจากโดยการเชื่อมโยงเหตุการณ์บนคอนเทนเนอร์คุณได้ระบุว่าคุณต้องการจัดการองค์ประกอบภายในคอนเทนเนอร์นั้นเท่านั้น .

กลับไปที่ตัวอย่างตารางของเราซึ่งหมายความว่าถ้าคุณมีตารางภายในเซลล์ตารางมันจะไม่ตรงกับเซลล์ตารางที่มีตาราง:


3

โดยพื้นฐานแล้วการเชื่อมโยงองค์ประกอบเข้าด้วยกัน .clickใช้กับ DOM ปัจจุบันในขณะที่.on(โดยใช้การมอบหมาย) จะยังคงใช้ได้สำหรับองค์ประกอบใหม่ที่เพิ่มใน DOM หลังจากการเชื่อมโยงเหตุการณ์

สิ่งที่ดีกว่าที่จะใช้ฉันจะบอกว่ามันขึ้นอยู่กับกรณี

ตัวอย่าง:

<ul id="todo">
   <li>Do 1</li>
   <li>Do 2</li>
   <li>Do 3</li>
   <li>Do 4</li>
</ul>

.Click กิจกรรม:

$("li").click(function () {
   $(this).remove ();
});

กิจกรรม. on:

$("#todo").on("click", "li", function () {
   $(this).remove();
});

โปรดทราบว่าฉันได้แยกตัวเลือกใน. on ฉันจะอธิบายว่าทำไม

ให้เราสมมติว่าหลังจากสมาคมนี้ให้เราทำสิ่งต่อไปนี้:

$("#todo").append("<li>Do 5</li>");

นั่นคือที่ที่คุณจะสังเกตเห็นความแตกต่าง

หากกิจกรรมมีการเชื่อมโยงผ่าน. คลิกภารกิจ 5 จะไม่เชื่อฟังเหตุการณ์คลิกดังนั้นจะไม่ถูกลบออก

หากมีการเชื่อมโยงผ่าน. on โดยมีตัวเลือกแยกต่างหากก็จะเชื่อฟัง


2

เพื่อให้เข้าใจถึงการมอบหมายเหตุการณ์ก่อนอื่นเราต้องรู้ว่าทำไมและเมื่อใดที่เราต้องการหรือต้องการการมอบหมายกิจกรรม

อาจมีหลายกรณี แต่ให้หารือเกี่ยวกับกรณีใช้งานใหญ่สองกรณีสำหรับการมอบหมายเหตุการณ์ 1. กรณีแรกคือเมื่อเรามีองค์ประกอบที่มีองค์ประกอบย่อย ๆ มากมายที่เราสนใจในกรณีนี้แทนที่จะเพิ่มตัวจัดการเหตุการณ์ให้กับองค์ประกอบย่อยทั้งหมดเราเพียงแค่เพิ่มองค์ประกอบหลักแล้วกำหนด องค์ประกอบลูกเหตุการณ์ถูกไล่ออก

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

สมมติว่าคุณมีรายการ 0, 10 หรือ 100 รายการใน DOM เมื่อคุณโหลดหน้าของคุณและมีอีกหลายรายการที่รออยู่ในมือของคุณเพื่อเพิ่มในรายการ ดังนั้นจึงไม่มีวิธีแนบตัวจัดการเหตุการณ์สำหรับองค์ประกอบในอนาคตหรือองค์ประกอบเหล่านั้นยังไม่ได้เพิ่มใน DOM และยังอาจมีรายการจำนวนมากดังนั้นจึงไม่มีประโยชน์ที่จะมีตัวจัดการเหตุการณ์หนึ่งตัวแนบอยู่กับแต่ละรายการ ของพวกเขา.

การมอบหมายกิจกรรม

เอาล่ะดังนั้นเพื่อที่จะพูดคุยเกี่ยวกับการมอบหมายเหตุการณ์แนวคิดแรกที่เราต้องพูดถึงคือการจัดอีเวนท์

การทำ bubbling ของเหตุการณ์: bubbling ของ เหตุการณ์หมายความว่าเมื่อมีเหตุการณ์ถูกเรียกใช้หรือถูกเรียกใช้ในองค์ประกอบ DOM บางตัวอย่างเช่นโดยการคลิกที่ปุ่มของเราที่นี่ในภาพด้านล่างจากนั้นเหตุการณ์เดียวกันที่แน่นอนจะถูกเรียกใช้ในองค์ประกอบหลักทั้งหมด

ป้อนคำอธิบายรูปภาพที่นี่

เหตุการณ์ถูกยิงครั้งแรกที่ปุ่ม แต่จากนั้นจะถูกยิงในองค์ประกอบหลักทั้งหมดทีละครั้งดังนั้นมันจะยิงในย่อหน้าไปยังส่วนองค์ประกอบหลักและจริง ๆ แล้วขึ้นไปบนต้นไม้ DOM จนกระทั่งองค์ประกอบ HTML ซึ่งเป็นรูต ดังนั้นเราจึงบอกว่าเหตุการณ์ระเบิดขึ้นภายในต้นไม้ DOM และนั่นคือเหตุผลที่เรียกว่าเดือดปุด ๆ

1 2 3 4

องค์ประกอบเป้าหมาย:องค์ประกอบที่เหตุการณ์ถูกยิงครั้งแรกที่เรียกว่าองค์ประกอบเป้าหมายดังนั้นองค์ประกอบที่ทำให้เกิดเหตุการณ์ที่เกิดขึ้นจะเรียกว่าองค์ประกอบเป้าหมาย ในตัวอย่างข้างต้นของเราที่นี่แน่นอนว่าปุ่มที่ถูกคลิก ส่วนที่สำคัญคือองค์ประกอบเป้าหมายนี้ถูกเก็บไว้เป็นคุณสมบัติในวัตถุเหตุการณ์ซึ่งหมายความว่าองค์ประกอบหลักทั้งหมดที่เหตุการณ์จะเริ่มทำงานจะทราบองค์ประกอบเป้าหมายของเหตุการณ์ดังนั้นเมื่อมีการเริ่มกิจกรรมครั้งแรก

สิ่งนี้นำเราไปสู่การมอบหมายกิจกรรมเพราะหากเหตุการณ์นั้นเกิดขึ้นในต้นไม้ DOM และถ้าเรารู้ว่าเหตุการณ์ถูกไล่ออกเราสามารถแนบตัวจัดการเหตุการณ์เข้ากับองค์ประกอบหลักและรอเหตุการณ์ที่จะเกิดขึ้นและเราสามารถ จากนั้นทำสิ่งที่เราตั้งใจจะทำกับองค์ประกอบเป้าหมายของเรา เทคนิคนี้เรียกว่าการมอบหมายกิจกรรม ในตัวอย่างนี้ที่นี่เราสามารถเพิ่มตัวจัดการเหตุการณ์ให้กับองค์ประกอบหลัก

เอาล่ะอีกครั้งการมอบหมายกิจกรรมคือการไม่ตั้งค่าตัวจัดการเหตุการณ์ในองค์ประกอบดั้งเดิมที่เราสนใจ แต่เพื่อแนบไปกับองค์ประกอบหลักและโดยทั่วไปจะจับเหตุการณ์ที่นั่นเพราะมันทำให้เกิดฟองขึ้น จากนั้นเราสามารถดำเนินการกับองค์ประกอบที่เราสนใจในการใช้คุณสมบัติองค์ประกอบเป้าหมาย

ตัวอย่าง: ตอนนี้สมมติว่าเรามีสองรายการในหน้าของเราหลังจากเพิ่มรายการในรายการเหล่านั้นโดยทางโปรแกรมเราต้องการลบหนึ่งรายการหรือมากกว่าจากรายการเหล่านั้น การใช้การมอบหมายเหตุการณ์ทำให้เราสามารถบรรลุเป้าหมายของเราได้อย่างง่ายดาย

<div class="body">
    <div class="top">

    </div>
    <div class="bottom">
        <div class="other">
            <!-- other bottom elements -->
        </div>
        <div class="container clearfix">
            <div class="income">
                <h2 class="icome__title">Income</h2>
                <div class="income__list">
                    <!-- list items -->
                </div>
            </div>
            <div class="expenses">
                <h2 class="expenses__title">Expenses</h2>
                <div class="expenses__list">
                    <!-- list items -->
                </div>
            </div>
        </div>
    </div>
</div>

การเพิ่มรายการในรายการเหล่านั้น:

const DOMstrings={
        type:{
            income:'inc',
            expense:'exp'
        },
        incomeContainer:'.income__list',
        expenseContainer:'.expenses__list',
        container:'.container'
   }


var addListItem = function(obj, type){
        //create html string with the place holder
        var html, element;
        if(type===DOMstrings.type.income){
            element = DOMstrings.incomeContainer
            html = `<div class="item clearfix" id="inc-${obj.id}">
            <div class="item__description">${obj.descripiton}</div>
            <div class="right clearfix">
                <div class="item__value">${obj.value}</div>
                <div class="item__delete">
                    <button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button>
                </div>
            </div>
        </div>`
        }else if (type ===DOMstrings.type.expense){
            element=DOMstrings.expenseContainer;
            html = ` <div class="item clearfix" id="exp-${obj.id}">
            <div class="item__description">${obj.descripiton}</div>
            <div class="right clearfix">
                <div class="item__value">${obj.value}</div>
                <div class="item__percentage">21%</div>
                <div class="item__delete">
                    <button class="item__delete--btn"><i class="ion-ios-close-outline"></i></button>
                </div>
            </div>
        </div>`
        }
        var htmlObject = document.createElement('div');
        htmlObject.innerHTML=html;
        document.querySelector(element).insertAdjacentElement('beforeend', htmlObject);
    }

ลบรายการ:

var ctrlDeleteItem = function(event){
       // var itemId = event.target.parentNode.parentNode.parentNode.parentNode.id;
        var parent = event.target.parentNode;
        var splitId, type, ID;
        while(parent.id===""){
            parent = parent.parentNode
        }
        if(parent.id){
            splitId = parent.id.split('-');
            type = splitId[0];
            ID=parseInt(splitId[1]);
        }

        deleteItem(type, ID);
        deleteListItem(parent.id);
 }

 var deleteItem = function(type, id){
        var ids, index;
        ids = data.allItems[type].map(function(current){
            return current.id;
        });
        index = ids.indexOf(id);
        if(index>-1){
            data.allItems[type].splice(index,1);
        }
    }

  var deleteListItem = function(selectorID){
        var element = document.getElementById(selectorID);
        element.parentNode.removeChild(element);
    }

1

ผู้รับมอบสิทธิ์ใน C # จะคล้ายกับตัวชี้ฟังก์ชันใน C หรือ C ++ การใช้ผู้รับมอบสิทธิ์อนุญาตให้โปรแกรมเมอร์เขียนแค็ปซูลการอ้างอิงไปยังวิธีการภายในวัตถุผู้รับมอบสิทธิ์ วัตถุผู้รับมอบสิทธิ์นั้นสามารถส่งผ่านไปยังรหัสที่สามารถเรียกวิธีการอ้างอิงโดยไม่ต้องรู้เวลารวบรวมวิธีการที่จะถูกเรียก

ดูลิงค์นี้ -> http://www.akadia.com/services/dotnet_delegates_and_events.html


5
ฉันจะไม่ลงคะแนนนี้เนื่องจากอาจเป็นคำตอบที่ถูกต้องสำหรับคำถามต้นฉบับ แต่ตอนนี้คำถามเกี่ยวกับการมอบหมายตัวแทน DOM และ Javascript โดยเฉพาะ
iandotkelly

1

การมอบหมายกิจกรรมใช้คุณสมบัติสองอย่างที่มักถูกมองข้ามของเหตุการณ์ JavaScript: การสร้างเหตุการณ์และองค์ประกอบเป้าหมายเมื่อมีเหตุการณ์ที่เกิดขึ้นกับองค์ประกอบเช่นการคลิกเมาส์ที่ปุ่มเหตุการณ์เดียวกันจะถูกเรียกใช้บนบรรพบุรุษขององค์ประกอบนั้น . กระบวนการนี้เรียกว่า bubbling ของเหตุการณ์ เหตุการณ์ที่เกิดขึ้นฟองอากาศจากองค์ประกอบที่กำเนิดไปด้านบนของต้นไม้ DOM

ลองนึกภาพตาราง HTML ที่มี 10 คอลัมน์และ 100 แถวที่คุณต้องการให้บางสิ่งเกิดขึ้นเมื่อผู้ใช้คลิกที่เซลล์ตาราง ตัวอย่างเช่นฉันเคยทำให้แต่ละเซลล์ของตารางขนาดนั้นสามารถแก้ไขได้เมื่อคลิก การเพิ่มตัวจัดการเหตุการณ์ให้กับแต่ละ 1000 เซลล์จะเป็นปัญหาด้านประสิทธิภาพที่สำคัญและอาจเป็นสาเหตุของการรั่วไหลของหน่วยความจำที่เบราว์เซอร์ล้มเหลว คุณสามารถเพิ่มตัวจัดการเหตุการณ์เพียงหนึ่งตัวในองค์ประกอบตารางแทนเหตุการณ์การคลิกและกำหนดเซลล์ที่ถูกคลิกแทน


0
การมอบหมายกิจกรรม

แนบผู้ฟังเหตุการณ์เข้ากับองค์ประกอบหลักที่จะยิงเมื่อมีเหตุการณ์เกิดขึ้นในองค์ประกอบลูก

การเผยแพร่เหตุการณ์

เมื่อเหตุการณ์เคลื่อนผ่าน DOM จากชายด์ไปยังองค์ประกอบพาเรนต์นั่นเรียกว่าการเผยแพร่เหตุการณ์เนื่องจากกิจกรรมเผยแพร่หรือย้ายผ่าน DOM

ในตัวอย่างนี้เหตุการณ์ (onclick) จากปุ่มจะถูกส่งผ่านไปยังย่อหน้าหลัก

$(document).ready(function() {

    $(".spoiler span").hide();

    /* add event onclick on parent (.spoiler) and delegate its event to child (button) */
    $(".spoiler").on( "click", "button", function() {
    
        $(".spoiler button").hide();    
    
        $(".spoiler span").show();
    
    } );

});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

<p class="spoiler">
    <span>Hello World</span>
    <button>Click Me</button>
</p>

Codepen

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