¿Qué es la delegación de eventos DOM?

230

¿Alguien puede explicar la delegación de eventos en JavaScript y cómo es útil?

4
361

La delegación de eventos DOM es un mecanismo de respuesta a eventos de interfaz de usuario a través de un único padre común en lugar de cada hijo, a través de la magia del "burbujeo" de eventos (también conocido como propagación de eventos).

Cuando se activa un evento en un elemento, ocurre lo siguiente :

The event is dispatched to its target EventTarget and any event listeners found there are triggered. Bubbling events will then trigger any additional event listeners found by following the EventTarget's parent chain upward, checking for any event listeners registered on each successive EventTarget. This upward propagation will continue up to and including the Document.

La propagación de eventos proporciona la base para la delegación de eventos en los navegadores. Ahora puede vincular un controlador de eventos a un solo elemento principal, y ese controlador se ejecutará siempre que el evento ocurra en cualquiera de sus nodos secundarios (y cualquiera de sus elementos secundarios a su vez). Esta es la delegación de eventos. Aquí hay un ejemplo de ello en la práctica:

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

Con ese ejemplo, si <li>hiciera clic en cualquiera de los nodos secundarios , vería una alerta de "click!", aunque no hay un controlador de clic vinculado al <li>que hizo clic. Si ligáramos onclick="..."a cada <li>uno, obtendría el mismo efecto.

Entonces, ¿cuál es el beneficio?

Imagine que ahora tiene la necesidad de agregar dinámicamente nuevos <li>elementos a la lista anterior a través de la manipulación DOM:

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

Sin usar la delegación de eventos, tendría que "volver a vincular" el "onclick"controlador de eventos al nuevo <li>elemento para que actúe de la misma manera que sus hermanos. Con la delegación de eventos no necesitas hacer nada. Simplemente agregue el nuevo <li>a la lista y listo.

Esto es absolutamente fantástico para aplicaciones web con controladores de eventos vinculados a muchos elementos, donde los nuevos elementos se crean y / o eliminan dinámicamente en el DOM. Con la delegación de eventos, el número de enlaces de eventos se puede reducir drásticamente moviéndolos a un elemento principal común, y el código que crea dinámicamente nuevos elementos sobre la marcha se puede desacoplar de la lógica de vincular sus controladores de eventos.

Otro beneficio de la delegación de eventos es que la huella de memoria total utilizada por los detectores de eventos disminuye (ya que el número de enlaces de eventos disminuye). Es posible que no suponga una gran diferencia para las páginas pequeñas que se descargan con frecuencia (es decir, el usuario navega a diferentes páginas con frecuencia). Pero para aplicaciones de larga duración, puede ser significativo. Hay algunas situaciones realmente difíciles de rastrear cuando los elementos eliminados del DOM todavía reclaman memoria (es decir, se filtran) y, a menudo, esta memoria filtrada está vinculada a un enlace de eventos. Con la delegación de eventos, puede destruir elementos secundarios sin riesgo de olvidarse de "desvincular" sus oyentes de eventos (ya que el oyente está en el antepasado). Este tipo de pérdidas de memoria se pueden contener (si no se eliminan, lo que a veces es muy difícil de hacer. Es decir, te estoy mirando).

A continuación, se muestran algunos ejemplos de códigos concretos mejores de delegación de eventos:

10
  • Tengo acceso prohibido al abrir su tercer enlace Delegación de eventos sin una biblioteca javascript y +1 para su último enlace 15/07/2013 a las 12:46
  • Hola, gracias por una gran explicación. Sin embargo, todavía estoy confundido acerca de un cierto detalle: la forma en que entiendo el flujo de eventos del árbol DOM (como se puede ver en 3.1. Despacho de eventos y flujo de eventos DOM ), el objeto de evento se propaga hasta que alcanza el elemento de destino y luego aparece. ¿Por qué puede llegar a los elementos secundarios de un nodo si el padre de este nodo es el objetivo del evento en cuestión? por ejemplo, ¿cómo se puede propagar el evento a <li>cuándo debería detenerse <ul>? Si mi pregunta aún no está clara o necesita un hilo por separado, estaré encantado de complacerlo.
    Imad
    11/04/2017 a las 9:14
  • @Aetos: > ¿Por qué puede llegar a los elementos secundarios de un nodo si el padre de este nodo es el objetivo del evento en cuestión? No puede, según tengo entendido. El evento termina la fase 1 (captura) en el padre del objetivo, entra en la fase 2 (objetivo) en el objetivo mismo, luego entra en la fase 3 (burbujeo) comenzando en el padre del objetivo. En ninguna parte llega a un hijo del objetivo. 12/04/2017 a las 15:01
  • @Crescent Fresh, entonces, ¿cómo se aplica el evento en el nodo secundario si nunca lo alcanza?
    Imad
    12/04/2017 a las 15:19
  • 1
    Realmente gran respuesta. Gracias por explicar la delegación del evento con hechos relevantes. ¡Gracias!
    Kshitij
    1/10/19 a las 12:44
40

La delegación de eventos le permite evitar agregar detectores de eventos a nodos específicos; en su lugar, el detector de eventos se agrega a un padre. Ese oyente de eventos analiza los eventos burbujeados para encontrar una coincidencia en los elementos secundarios.

Ejemplo de JavaScript:

Digamos que tenemos un elemento UL principal con varios elementos secundarios:

<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>
</ul>

Digamos también que algo debe suceder cuando se hace clic en cada elemento secundario. Puede agregar un detector de eventos separado a cada elemento de LI individual, pero ¿qué pasa si los elementos de LI se agregan y eliminan con frecuencia de la lista? Agregar y eliminar detectores de eventos sería una pesadilla, especialmente si el código de adición y eliminación se encuentra en diferentes lugares dentro de su aplicación. La mejor solución es agregar un detector de eventos al elemento UL principal. Pero si agrega el detector de eventos al padre, ¿cómo sabrá en qué elemento se hizo clic?

Simple: cuando el evento llega al elemento UL, verifica la propiedad de destino del objeto de evento para obtener una referencia al nodo real en el que se hizo clic. Aquí hay un fragmento de JavaScript muy básico que ilustra la delegación de eventos:

// 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!");
   }
});

Comience agregando un detector de eventos de clic al elemento principal. Cuando se activa el detector de eventos, verifique el elemento del evento para asegurarse de que sea el tipo de elemento al que reaccionar. Si es un elemento LI, boom: ¡tenemos lo que necesitamos! Si no es un elemento que queremos, el evento se puede ignorar. Este ejemplo es bastante simple: UL y LI es una comparación sencilla. Intentemos algo más difícil. Tengamos un DIV padre con muchos hijos, pero todo lo que nos importa es una etiqueta A con la clase de 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....
            }
        }
    }
  }
});

http://davidwalsh.name/event-delegate

1
8

La delegación de eventos dom es algo diferente de la definición informática.

Se refiere al manejo de eventos de propagación de muchos elementos, como las celdas de una tabla, de un objeto principal, como la tabla. Puede simplificar el código, especialmente al agregar o eliminar elementos, y ahorra algo de memoria.

7

El concepto de delegación

Si hay muchos elementos dentro de un padre y desea manejar eventos en ellos, no vincule los controladores a cada elemento. En su lugar, vincule el controlador único a su padre y obtenga el hijo de event.target. Este sitio proporciona información útil sobre cómo implementar la delegación de eventos. http://javascript.info/tutorial/event-delegation

7

La delegación de eventos está manejando un evento que burbujea usando un controlador de eventos en un elemento contenedor, pero solo activa el comportamiento del controlador de eventos si el evento ocurrió en un elemento dentro del contenedor que coincide con una condición dada. Esto puede simplificar el manejo de eventos en elementos dentro del contenedor.

Por ejemplo, suponga que desea manejar un clic en cualquier celda de la tabla en una tabla grande. Usted podría escribir un bucle para conectar un controlador de clic a cada célula ... o se puede conectar un controlador de clic en la delegación de la tabla de eventos y utilizar para activar sólo para celdas de la tabla (y no los encabezados de tabla, o el espacio en blanco dentro de una fila alrededor de las celdas, etc.).

También es útil cuando va a agregar y eliminar elementos del contenedor, porque no tiene que preocuparse por agregar y eliminar controladores de eventos en esos elementos; simplemente enganche el evento en el contenedor y maneje el evento cuando burbujee.

Aquí hay un ejemplo simple (es intencionalmente detallado para permitir una explicación en línea): Manejo de un clic en cualquier tdelemento en una tabla contenedor:

// 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>

Antes de entrar en detalles, recordemos cómo funcionan los eventos DOM.

Los eventos DOM se envían desde el documento al elemento de destino (la fase de captura ), y luego se envían desde el elemento de destino al documento (la fase de propagación ). Este gráfico en la antigua especificación de eventos DOM3 (ahora reemplazado, pero el gráfico sigue siendo válido) lo muestra muy bien:

ingrese la descripción de la imagen aquí

No todos los eventos burbujean, pero la mayoría sí, incluido click.

Los comentarios en el ejemplo de código anterior describen cómo funciona. matchescomprueba si un elemento coincide con un selector de CSS, pero, por supuesto, puede comprobar si algo coincide con sus criterios de otras formas si no desea utilizar un selector de CSS.

Ese código está escrito para indicar los pasos individuales de manera detallada, pero en navegadores vagamente modernos (y también en IE si usa un polyfill), puede usar closesty en containslugar del bucle:

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

Ejemplo en vivo:

// Handle the event on the container
document.getElementById("container").addEventListener("click", function(event) {
    var target = event.target.closest("td");
    if (target && this.contains(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>

closestcomprueba el elemento al que lo llama para ver si coincide con el selector de CSS dado y, si lo hace, devuelve el mismo elemento; si no, verifica el elemento padre para ver si coincide y, si es así, devuelve el padre; si no, comprueba el padre del padre, etc. De modo que encuentra el elemento "más cercano" en la lista de ancestros que coincide con el selector. Dado que eso podría ir más allá del elemento contenedor, el código anterior usa containspara verificar que si se encontró un elemento coincidente, está dentro del contenedor, ya que al enganchar el evento en el contenedor, ha indicado que solo desea manejar elementos dentro de ese contenedor .

Volviendo a nuestro ejemplo de tabla, eso significa que si tiene una tabla dentro de una celda de tabla, no coincidirá con la celda de tabla que contiene la tabla:

// Handle the event on the container
document.getElementById("container").addEventListener("click", function(event) {
    var target = event.target.closest("td");
    if (target && this.contains(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;
}
<!-- The table wrapped around the #container table -->
<table>
    <tbody>
        <tr>
            <td>
                <!-- This cell doesn't get matched, thanks to the `this.contains(target)` check -->
                <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>
            </td>
            <td>
                This is next to the container table
            </td>
        </tr>
    </tbody>
</table>
6

La delegación es una técnica en la que un objeto expresa cierto comportamiento al exterior, pero en realidad delega la responsabilidad de implementar ese comportamiento a un objeto asociado. Al principio, esto suena muy similar al patrón de proxy, pero tiene un propósito muy diferente. La delegación es un mecanismo de abstracción que centraliza el comportamiento del objeto (método).

Hablado generalmente: use la delegación como alternativa a la herencia. La herencia es una buena estrategia, cuando existe una relación cercana entre el objeto padre y el hijo, sin embargo, la herencia une los objetos muy estrechamente. A menudo, la delegación es la forma más flexible de expresar una relación entre clases.

Este patrón también se conoce como "cadenas de proxy". Varios otros patrones de diseño utilizan la delegación: el estado, la estrategia y los patrones de visitantes dependen de ella.

1
  • Buena explicación. En el ejemplo del <ul> con varios <li> hijos, aparentemente los <li> son los que manejan la lógica del clic, pero no es así porque "delegan" esta lógica en el padre <ul> 15/01/19 a las 0:43
3

Para comprender la delegación de eventos, primero necesitamos saber por qué y cuándo realmente necesitamos o queremos la delegación de eventos.

Puede haber muchos casos, pero analicemos dos grandes casos de uso para la delegación de eventos. 1. El primer caso es cuando tenemos un elemento con muchos elementos secundarios que nos interesan. En este caso, en lugar de agregar un controlador de eventos a todos estos elementos secundarios, simplemente lo agregamos al elemento principal y luego determinamos en qué elemento hijo se disparó el evento.

El segundo caso de uso para la delegación de eventos es cuando queremos un controlador de eventos adjunto a un elemento que aún no está en el DOM cuando se carga nuestra página. Eso es, por supuesto, porque no podemos agregar un controlador de eventos a algo que no está en nuestra página, por lo que, en caso de desaprobación, estamos codificando.

Suponga que tiene una lista de 0, 10 o 100 elementos en el DOM cuando carga su página, y hay más elementos esperando en su mano para agregarlos a la lista. Por lo tanto, no hay forma de adjuntar un controlador de eventos para los elementos futuros o esos elementos aún no se agregaron en el DOM, y también puede haber muchos elementos, por lo que no sería útil tener un controlador de eventos adjunto a cada uno. de ellos.

Delegación de eventos

Muy bien, para hablar de delegación de eventos, el primer concepto del que realmente necesitamos hablar es el burbujeo de eventos.

Generación de eventos: la propagación de eventos significa que cuando un evento se activa o activa en algún elemento DOM, por ejemplo, al hacer clic en nuestro botón aquí en la imagen de abajo, entonces el mismo evento exacto también se activa en todos los elementos principales.

ingrese la descripción de la imagen aquí

El evento se activa primero en el botón, pero luego también se activará en todos los elementos principales uno a la vez, por lo que también se activará en el párrafo de la sección del elemento principal y, en realidad, todo el camino hacia arriba en un árbol DOM. hasta el elemento HTML que es la raíz. Entonces decimos que el evento surge dentro del árbol DOM, y por eso se llama burbujeo.

1 2 3 4

Elemento de destino: el elemento en el que el evento se disparó por primera vez se llama elemento de destino, por lo que el elemento que provocó que ocurriera el evento se llama elemento de destino. En nuestro ejemplo anterior, es, por supuesto, el botón en el que se hizo clic. La parte importante es que este elemento de destino se almacena como una propiedad en el objeto de evento. Esto significa que todos los elementos principales en los que el evento también se activará conocerán el elemento de destino del evento, por lo que el lugar donde se activó el evento por primera vez.

Eso nos lleva a la delegación de eventos porque si el evento aparece en el árbol DOM, y si sabemos dónde se disparó el evento, simplemente podemos adjuntar un controlador de eventos a un elemento principal y esperar a que el evento aumente, y podemos luego haga lo que pretendamos hacer con nuestro elemento de destino. Esta técnica se llama delegación de eventos. En este ejemplo, podríamos simplemente agregar el controlador de eventos al elemento principal.

De acuerdo, de nuevo, la delegación de eventos no consiste en configurar el controlador de eventos en el elemento original que nos interesa, sino en adjuntarlo a un elemento principal y, básicamente, capturar el evento allí porque surge. Luego podemos actuar sobre el elemento en el que estamos interesados ​​usando la propiedad del elemento de destino.

Ejemplo: Ahora supongamos que tenemos dos elementos de lista en nuestra página, después de agregar elementos en esa lista mediante programación, queremos eliminar uno o más elementos de ellos. Usando la técnica de delegación de eventos podemos lograr nuestro propósito fácilmente.

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

Agregar elementos en esa lista:

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

Eliminar ítems:

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

Básicamente es cómo se hace la asociación con el elemento. .clickse aplica al DOM actual, mientras que .on(usando la delegación) seguirá siendo válido para los nuevos elementos agregados al DOM después de la asociación del evento.

Cuál es mejor de usar, yo diría que depende del caso.

Ejemplo:

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

.Haga clic en Evento:

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

Evento .en:

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

Tenga en cuenta que he separado el selector en .on. Explicaré por qué.

Supongamos que después de esta asociación, hagamos lo siguiente:

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

Ahí es donde notarás la diferencia.

Si el evento se asoció mediante .click, la tarea 5 no obedecerá al evento de clic y, por lo tanto, no se eliminará.

Si se asoció a través de .on, con el selector separado, obedecerá.

1

Un delegado en C # es similar a un puntero de función en C o C ++. El uso de un delegado permite al programador encapsular una referencia a un método dentro de un objeto delegado. El objeto delegado se puede pasar al código que puede llamar al método referenciado, sin tener que saber en el momento de la compilación qué método se invocará.

Vea este enlace -> http://www.akadia.com/services/dotnet_delegates_and_events.html

1
  • 6
    No voy a rechazar esto, ya que probablemente fue una respuesta correcta a la pregunta original, pero la pregunta ahora es específicamente sobre la delegación de eventos DOM y Javascript. 6 feb 2013 a las 16:06
1

La delegación de eventos hace uso de dos características de los eventos de JavaScript que a menudo se pasan por alto: la propagación de eventos y el elemento de destino.Cuando un evento se activa en un elemento, por ejemplo, un clic del mouse en un botón, el mismo evento también se activa en todos los antepasados ​​de ese elemento. . Este proceso se conoce como propagación de eventos; el evento surge desde el elemento de origen hasta la parte superior del árbol DOM.

Imagine una tabla HTML con 10 columnas y 100 filas en la que desea que suceda algo cuando el usuario hace clic en una celda de la tabla. Por ejemplo, una vez tuve que hacer que cada celda de una tabla de ese tamaño fuera editable al hacer clic. Agregar controladores de eventos a cada una de las 1000 celdas sería un problema de rendimiento importante y, potencialmente, una fuente de pérdidas de memoria que bloquean el navegador. En su lugar, al usar la delegación de eventos, agregaría solo un controlador de eventos al elemento de la tabla, interceptaría el evento de clic y determinaría en qué celda se hizo clic.

0
Delegación de eventos

Adjunte un detector de eventos a un elemento principal que se activa cuando ocurre un evento en un elemento secundario.

Propagación de eventos

Cuando un evento se mueve a través del DOM de un elemento secundario a un elemento principal, eso se llama Propagación de eventos , porque el evento se propaga o se mueve a través del DOM.

En este ejemplo, un evento (onclick) de un botón se pasa al párrafo principal.

$(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