Adakah yang bisa menjelaskan delegasi acara dalam JavaScript dan apa manfaatnya?
Adakah yang bisa menjelaskan delegasi acara dalam JavaScript dan apa manfaatnya?
Jawaban:
Delegasi acara DOM adalah mekanisme menanggapi ui-peristiwa melalui orang tua tunggal tunggal daripada setiap anak, melalui keajaiban acara "menggelegak" (alias propagasi acara).
Ketika suatu peristiwa dipicu pada suatu elemen, berikut ini terjadi :
Acara dikirim ke targetnya
EventTarget
dan setiap pendengar acara ditemukan di sana dipicu. Gelembung acara kemudian akan memicu pendengar acara tambahan yang ditemukan dengan mengikutiEventTarget
rantai induk ke atas , memeriksa untuk setiap pendengar acara yang terdaftar pada setiap Target Acara berturut-turut. Propagasi naik ini akan berlanjut hingga dan termasukDocument
.
Gelembung acara menyediakan dasar untuk delegasi acara di browser. Sekarang Anda dapat mengikat event handler ke elemen induk tunggal, dan handler itu akan dieksekusi setiap kali event tersebut terjadi pada salah satu node anak-anaknya (dan juga anak-anak mereka). Ini adalah delegasi acara. Berikut ini contohnya dalam praktik:
<ul onclick="alert(event.type + '!')">
<li>One</li>
<li>Two</li>
<li>Three</li>
</ul>
Dengan contoh itu jika Anda mengklik salah satu <li>
simpul anak , Anda akan melihat lansiran "click!"
, meskipun tidak ada penangan klik yang terikat pada yang <li>
Anda klik. Jika kami terikat onclick="..."
satu sama lain <li>
Anda akan mendapatkan efek yang sama.
Jadi apa untungnya?
Bayangkan Anda sekarang memiliki kebutuhan untuk secara dinamis menambahkan <li>
item baru ke daftar di atas melalui manipulasi DOM:
var newLi = document.createElement('li');
newLi.innerHTML = 'Four';
myUL.appendChild(newLi);
Tanpa menggunakan delegasi acara Anda harus "mengubah" "onclick"
event handler ke <li>
elemen baru , agar dapat bertindak dengan cara yang sama seperti saudara kandungnya. Dengan delegasi acara, Anda tidak perlu melakukan apa pun. Tambahkan saja yang baru <li>
ke daftar dan selesai.
Ini benar-benar fantastis untuk aplikasi web dengan penangan acara terikat dengan banyak elemen, di mana elemen baru dibuat dan / atau dihapus secara dinamis di DOM. Dengan pendelegasian acara, jumlah binding acara dapat dikurangi secara drastis dengan memindahkannya ke elemen induk yang sama, dan kode yang secara dinamis membuat elemen baru dengan cepat dapat dipisahkan dari logika pengikatan event handler mereka.
Manfaat lain untuk delegasi acara adalah bahwa total jejak memori yang digunakan oleh pendengar acara turun (karena jumlah binding acara turun). Ini mungkin tidak membuat banyak perbedaan pada halaman-halaman kecil yang sering dibongkar (mis. Pengguna menavigasi ke halaman yang berbeda sering). Tetapi untuk aplikasi berumur panjang, ini bisa menjadi signifikan. Ada beberapa situasi yang sangat sulit untuk dilacak ketika elemen yang dihapus dari DOM masih mengklaim memori (misalnya, mereka bocor), dan seringkali memori yang bocor ini terikat dengan peristiwa yang mengikat. Dengan delegasi acara, Anda bebas untuk menghancurkan elemen anak tanpa risiko lupa untuk "melepaskan" pendengar acara mereka (karena pendengarnya adalah leluhur). Jenis-jenis kebocoran memori ini kemudian dapat ditampung (jika tidak dihilangkan, yang kadang-kadang sangat sulit dilakukan. Yaitu saya sedang melihat Anda).
Berikut adalah beberapa contoh kode konkret dari delegasi acara yang lebih baik:
focus
dan blur
acara (yang tidak gelembung)<li>
kapan harus berhenti <ul>
? Jika pertanyaan saya masih belum jelas atau membutuhkan utas terpisah, saya akan dengan senang hati menurutinya.
Delegasi acara memungkinkan Anda untuk menghindari menambahkan pendengar acara ke node tertentu; sebagai gantinya, pendengar acara ditambahkan ke satu orangtua. Pendengar acara itu menganalisis peristiwa yang menggelembung untuk menemukan kecocokan pada elemen anak.
Contoh JavaScript:
Katakanlah kita memiliki elemen UL induk dengan beberapa elemen anak:
<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>
Katakan juga bahwa sesuatu harus terjadi ketika setiap elemen anak diklik. Anda bisa menambahkan pendengar acara terpisah untuk setiap elemen LI individu, tetapi bagaimana jika elemen LI sering ditambahkan dan dihapus dari daftar? Menambah dan menghapus pendengar acara akan menjadi mimpi buruk, terutama jika kode penambahan dan penghapusan berada di tempat yang berbeda dalam aplikasi Anda. Solusi yang lebih baik adalah menambahkan pendengar acara ke elemen UL induk. Tetapi jika Anda menambahkan pendengar acara ke induk, bagaimana Anda tahu elemen mana yang diklik?
Sederhana: ketika acara muncul hingga elemen UL, Anda memeriksa properti target objek acara untuk mendapatkan referensi ke simpul yang diklik aktual. Berikut cuplikan JavaScript yang sangat mendasar yang menggambarkan delegasi acara:
// 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!");
}
});
Mulai dengan menambahkan pendengar peristiwa klik ke elemen induk. Ketika pendengar peristiwa dipicu, periksa elemen acara untuk memastikan itu jenis elemen untuk bereaksi. Jika itu adalah elemen LI, boom: kita memiliki apa yang kita butuhkan! Jika itu bukan elemen yang kita inginkan, acara tersebut dapat diabaikan. Contoh ini cukup sederhana - UL dan LI adalah perbandingan langsung. Mari kita coba sesuatu yang lebih sulit. Mari kita memiliki DIV orang tua dengan banyak anak tetapi yang kita pedulikan hanyalah tag A dengan kelas CSS classA:
// 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....
}
}
}
}
});
Pendelegasian acara dom adalah sesuatu yang berbeda dari definisi ilmu komputer.
Ini merujuk pada penanganan peristiwa gelembung dari banyak elemen, seperti sel tabel, dari objek induk, seperti tabel. Itu dapat membuat kode lebih sederhana, terutama saat menambahkan atau menghapus elemen, dan menghemat memori.
Delegasi adalah teknik di mana objek mengekspresikan perilaku tertentu ke luar tetapi pada kenyataannya mendelegasikan tanggung jawab untuk menerapkan perilaku itu ke objek terkait. Ini terdengar pada awalnya sangat mirip dengan pola proksi, tetapi melayani tujuan yang jauh berbeda. Delegasi adalah mekanisme abstraksi yang memusatkan perilaku objek (metode).
Secara umum: gunakan delegasi sebagai alternatif warisan. Warisan adalah strategi yang baik, ketika hubungan dekat ada di antara objek orang tua dan anak, namun, warisan objek pasangan sangat erat. Seringkali, delegasi adalah cara yang lebih fleksibel untuk mengekspresikan hubungan antar kelas.
Pola ini juga dikenal sebagai "rantai proxy". Beberapa pola desain lain menggunakan delegasi - Negara, Strategi dan Pola Pengunjung bergantung padanya.
Jika ada banyak elemen di dalam satu orangtua, dan Anda ingin menangani event mereka - jangan mengikat handler ke setiap elemen. Sebagai gantinya, ikat pawang tunggal ke orang tua mereka, dan dapatkan anak dari event.target. Situs ini menyediakan info berguna tentang cara mengimplementasikan delegasi acara. http://javascript.info/tutorial/event-delegation
Delegasi acara menangani suatu peristiwa yang menggelembung menggunakan pengendali event pada elemen kontainer, tetapi hanya mengaktifkan perilaku event handler jika peristiwa terjadi pada elemen dalam wadah yang cocok dengan kondisi tertentu. Ini dapat menyederhanakan penanganan acara pada elemen dalam wadah.
Misalnya, Anda ingin menangani klik pada sel tabel apa pun di tabel besar. Anda bisa menulis loop untuk menghubungkan handler klik ke setiap sel ... atau Anda bisa menghubungkan handler klik di atas meja dan menggunakan delegasi acara untuk memicu itu hanya untuk sel tabel (dan bukan header tabel, atau spasi putih dalam sebuah baris di sekitar sel, dll.).
Ini juga berguna ketika Anda akan menambahkan dan menghapus elemen dari wadah, karena Anda tidak perlu khawatir tentang menambah dan menghapus event handler pada elemen tersebut; cukup kaitkan acara di wadah dan tangani acara saat gelembung.
Berikut ini contoh sederhana (sengaja dibuat verbose untuk memungkinkan penjelasan inline): Menangani klik pada td
elemen apa pun di tabel kontainer:
// 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>
Sebelum membahas detailnya, mari kita mengingatkan diri kita sendiri bagaimana acara DOM bekerja.
Peristiwa DOM dikirim dari dokumen ke elemen target ( fase penangkapan ), dan kemudian gelembung dari elemen target kembali ke dokumen ( fase gelembung ). Grafik ini di spec peristiwa DOM3 lama (sekarang digantikan, tetapi grafik masih valid) menunjukkan dengan sangat baik:
Tidak semua acara menggelembung, tetapi sebagian besar melakukannya, termasuk click
.
Komentar dalam contoh kode di atas menjelaskan cara kerjanya. matches
memeriksa untuk melihat apakah suatu elemen cocok dengan pemilih CSS, tetapi tentu saja Anda dapat memeriksa apakah sesuatu cocok dengan kriteria Anda dengan cara lain jika Anda tidak ingin menggunakan pemilih CSS.
Kode itu ditulis untuk memanggil setiap langkah secara lisan, tetapi pada browser yang samar-samar modern (dan juga pada IE jika Anda menggunakan polyfill), Anda dapat menggunakan closest
dan contains
bukannya loop:
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");
}
Contoh Langsung:
closest
memeriksa elemen yang Anda panggil untuk melihat apakah itu cocok dengan pemilih CSS yang diberikan dan, jika ya, mengembalikan elemen yang sama; jika tidak, ia memeriksa elemen induk untuk melihat apakah cocok, dan mengembalikan induk jika demikian; jika tidak, ia memeriksa induk induk, dll. Jadi ia menemukan elemen "terdekat" dalam daftar leluhur yang cocok dengan pemilih. Karena itu mungkin melewati elemen kontainer, kode di atas digunakan contains
untuk memeriksa bahwa jika elemen yang cocok ditemukan, itu ada di dalam wadah - karena dengan mengaitkan acara pada wadah, Anda telah mengindikasikan bahwa Anda hanya ingin menangani elemen dalam wadah itu .
Kembali ke contoh tabel kami, itu berarti bahwa jika Anda memiliki tabel di dalam sel tabel, itu tidak akan cocok dengan sel tabel yang berisi tabel:
Ini pada dasarnya bagaimana asosiasi dibuat ke elemen. .click
berlaku untuk DOM saat ini, sementara .on
(menggunakan delegasi) akan terus berlaku untuk elemen baru yang ditambahkan ke DOM setelah asosiasi acara.
Mana yang lebih baik untuk digunakan, saya akan mengatakan itu tergantung pada kasusnya.
Contoh:
<ul id="todo">
<li>Do 1</li>
<li>Do 2</li>
<li>Do 3</li>
<li>Do 4</li>
</ul>
. Klik Acara:
$("li").click(function () {
$(this).remove ();
});
Acara .pada:
$("#todo").on("click", "li", function () {
$(this).remove();
});
Perhatikan bahwa saya telah memisahkan pemilih di .on. Saya akan menjelaskan alasannya.
Mari kita anggap bahwa setelah asosiasi ini, mari kita lakukan hal berikut:
$("#todo").append("<li>Do 5</li>");
Di situlah Anda akan melihat perbedaannya.
Jika acara dikaitkan dengan .click, tugas 5 tidak akan mematuhi acara klik, dan karenanya tidak akan dihapus.
Jika dikaitkan melalui .on, dengan selector terpisah, ia akan patuh.
Untuk memahami delegasi acara terlebih dahulu, kita perlu tahu mengapa dan kapan kita benar-benar membutuhkan atau menginginkan delegasi acara.
Mungkin ada banyak kasus tetapi mari kita bahas dua kasus penggunaan besar untuk delegasi acara. 1. Kasus pertama adalah ketika kita memiliki elemen dengan banyak elemen anak yang kita minati. Dalam kasus ini, alih-alih menambahkan event handler ke semua elemen anak ini, kita cukup menambahkannya ke elemen induk dan kemudian menentukan di mana elemen anak acara dipecat.
2.Kasus penggunaan kedua untuk delegasi acara adalah ketika kami ingin pengendali acara dilampirkan ke elemen yang belum ada di DOM saat halaman kami dimuat. Itu, tentu saja, karena kita tidak bisa menambahkan event handler ke sesuatu yang tidak ada di halaman kita, jadi dalam kasus penghinaan yang kita koding.
Misalkan Anda memiliki daftar 0, 10, atau 100 item di DOM ketika Anda memuat halaman Anda, dan lebih banyak item menunggu di tangan Anda untuk ditambahkan dalam daftar. Jadi tidak ada cara untuk melampirkan event handler untuk elemen-elemen di masa depan atau elemen-elemen tersebut belum ditambahkan di DOM, dan juga mungkin ada banyak item, jadi tidak akan berguna untuk memiliki satu event handler yang melekat pada masing-masing dari mereka.
Delegasi Acara
Baiklah, jadi untuk membicarakan tentang pendelegasian acara, konsep pertama yang sebenarnya perlu kita bicarakan adalah penggelembungan acara.
Gelembung peristiwa: Gelembung peristiwa berarti bahwa ketika suatu peristiwa dipecat atau dipicu pada beberapa elemen DOM, misalnya dengan mengklik tombol kami di sini pada gambar di bawah, maka peristiwa yang sama persis juga dipicu pada semua elemen induk.
Acara pertama kali diaktifkan pada tombol, tetapi kemudian juga akan ditembaki pada semua elemen induk satu per satu, sehingga juga akan menembak paragraf ke bagian elemen utama dan benar-benar sepanjang jalan di pohon DOM hingga elemen HTML yang merupakan root. Jadi kita katakan bahwa peristiwa itu meletus di dalam pohon DOM, dan itulah sebabnya itu disebut menggelegak.
Elemen target: Elemen di mana peristiwa itu pertama kali dipecat disebut elemen target, sehingga elemen yang menyebabkan peristiwa itu terjadi, disebut elemen target. Dalam contoh kami di atas di sini, tentu saja, tombol yang diklik. Bagian yang penting adalah bahwa elemen target ini disimpan sebagai properti di objek acara, Ini berarti bahwa semua elemen induk di mana acara juga akan menembak akan tahu elemen target acara, jadi di mana acara itu pertama kali dipecat.
Itu membawa kita ke delegasi acara karena jika acara muncul di pohon DOM, dan jika kita tahu di mana acara itu dipecat maka kita dapat dengan mudah melampirkan pengendali acara ke elemen induk dan menunggu acara tersebut muncul, dan kita dapat kemudian lakukan apa pun yang kami maksudkan dengan elemen target kami. Teknik ini disebut delegasi acara. Dalam contoh ini di sini, kita bisa menambahkan event handler ke elemen utama.
Baiklah, jadi sekali lagi, delegasi acara adalah untuk tidak mengatur event handler pada elemen asli yang kami minati tetapi untuk melampirkannya ke elemen induk dan, pada dasarnya, menangkap acara di sana karena itu menggelembung. Kami kemudian dapat bertindak pada elemen yang kami tertarik menggunakan properti elemen target.
Contoh: Sekarang mari kita asumsikan kita memiliki dua item daftar di halaman kita, setelah menambahkan item dalam daftar itu secara terprogram kita ingin menghapus satu atau lebih item dari mereka. Dengan menggunakan teknik delegasi acara, kita dapat mencapai tujuan dengan mudah.
<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>
Menambahkan item dalam daftar itu:
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);
}
Hapus item:
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);
}
Delegasi di C # mirip dengan pointer fungsi di C atau C ++. Menggunakan delegasi memungkinkan programmer untuk merangkum referensi ke metode di dalam objek delegasi. Objek delegasi kemudian dapat diteruskan ke kode yang dapat memanggil metode yang dirujuk, tanpa harus tahu pada waktu kompilasi metode mana yang akan dipanggil.
Lihat tautan ini -> http://www.akadia.com/services/dotnet_delegates_and_events.html
Delegasi acara memanfaatkan dua fitur yang sering diabaikan dari peristiwa JavaScript: peristiwa menggelegak dan elemen target. Ketika suatu peristiwa dipicu pada suatu elemen, misalnya klik mouse pada tombol, acara yang sama juga dipicu pada semua leluhur elemen itu. . Proses ini dikenal sebagai event bubbling; peristiwa muncul dari elemen yang berasal ke bagian atas pohon DOM.
Bayangkan sebuah tabel HTML dengan 10 kolom dan 100 baris di mana Anda menginginkan sesuatu terjadi ketika pengguna mengklik sel tabel. Sebagai contoh, saya pernah membuat setiap sel dari tabel dengan ukuran itu dapat diedit ketika diklik. Menambahkan event handler ke masing-masing 1000 sel akan menjadi masalah kinerja utama dan, berpotensi, sumber kebocoran memori browser-crashing. Alih-alih, menggunakan delegasi acara, Anda akan menambahkan hanya satu pengendali acara ke elemen tabel, memotong acara klik dan menentukan sel mana yang diklik.
Lampirkan pendengar peristiwa ke elemen induk yang menyala ketika suatu peristiwa terjadi pada elemen anak.
Propagasi AcaraKetika suatu peristiwa bergerak melalui DOM dari anak ke elemen induk, itu disebut Propagasi Peristiwa , karena peristiwa tersebut menyebar, atau bergerak melalui DOM.
Dalam contoh ini, suatu peristiwa (klik) dari suatu tombol akan diteruskan ke paragraf induk.
$(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>