Aprende a enviar eventos personalizados en JavaScript correctamente.

Los eventos de Javascript son una parte importante del ecosistema JS, ya que nos permiten saber cuándo ocurre un evento sin comprometer el rendimiento del navegador.

Puede crear sus propios eventos utilizando la CustomEventAPI para reaccionar a esos eventos con un detector de eventos, como suele hacer con los eventos existentes.

Escuchar evento

Como vamos a enviar eventos con la API CustomEvent, primero debemos escucharlos, de lo contrario, nunca obtendremos ningún resultado.

Recuerde que un evento solo se puede enviar en un elemento DOM (documento, entrada, botones, div, etc.). En este caso, el evento se nombrará "OurSuperEvent"y se enviará (en el siguiente paso) el document, por lo que el oyente también se agregará document.

var element = document;
// or 
// var element = document.getElementById("aRandomId");

element.addEventListener("OurSuperEvent", function (e) {
    // Esta es la información que recibimos del CustomEvent
    console.log("The custom data of the event is : ", e.detail);
    // El evento como sí mismo (objeto con propiedades como {srcElement, isTrusted, target, defaultPrevent, etc.})
    console.log("Event is : ",e);
}, false);

La propiedad detail del evento, contiene la información que envía cuando envía el evento.

Nota: como se dijo antes, el detector de eventos se ha agregado al elemento del documento. Por lo tanto, el evento también debe enviarse en el elemento del documento; de lo contrario, el evento nunca se escuchará, ya que no es el elemento que asignamos para este evento.

Envío de eventos personalizados

Ahora que tenemos un oyente que nos dice cuándo ocurre nuestro evento, necesita aprender cómo enviarlo.

En el oyente agregamos el oyente al documento, por lo tanto, nuestro evento (para ser escuchado) también se enviará en el documento.

var myData = {
    id: 1,
    name: "An imaginary name",
    customProperty:"I need to know this string when the event is dispatched",
    moreData: [1,2,4,5,6,7]
};

var element = document;
// or 
// var element = document.getElementById("aRandomId");

// El evento personalizado que recibe como primer parámetro el nombre del tipo de dispatchedEvent
var event = new CustomEvent("OurSuperEvent", { detail: myData });

element.dispatchEvent(event);

Como puede ver, la implementación de un evento personalizado es muy simple, minimalista y limpia.

Sin embargo (y siempre en el mundo javascript), algunos navegadores (Internet Explorer) no implementan la misma inicialización.

Mientras window.CustomEventexista un objeto en el navegador, no se puede llamar como constructor . En lugar de new CustomEvent(...), debe usar event = document.createEvent('CustomEvent') y luego event.initCustomEvent(...)como se muestra en el siguiente ejemplo:

var myData = {
    id: 1,
    name: "An imaginary name",
    customProperty:"I need to know this string when the event is dispatched",
    moreData: [1,2,4,5,6,7]
};

var element = document;
// or 
// var element = document.getElementById("aRandomId");

// Enviar un evento
var event = document.createEvent("CustomEvent");
event.initCustomEvent("OurSuperEvent", true, true, myData);
element.dispatchEvent(event);

Polyfill

Tenga en cuenta que la API CustomEvent no es compatible con algunas versiones del antiguo WebView basado en WebKit de Android. Afortunadamente, hay un polyfill disponible para esta función.

Este fragmento cubre el evento IE6. Esta secuencia de comandos rellena addEventListener, removeEventListener, dispatchEvent, CustomEvent y DOMContentLoaded. Tiene menos de medio kilobyte minificado y comprimido con gzip. 

Puede visitar el repositorio aquí y ver el código fuente , u obtener el polyfill directamente aquí:

// EventListener | CC0 | github.com/jonathantneal/EventListener

this.Element && Element.prototype.attachEvent && !Element.prototype.addEventListener && (function () {
	function addToPrototype(name, method) {
		Window.prototype[name] = HTMLDocument.prototype[name] = Element.prototype[name] = method;
	}

	// add
	addToPrototype("addEventListener", function (type, listener) {
		var
		target = this,
		listeners = target.addEventListener.listeners = target.addEventListener.listeners || {},
		typeListeners = listeners[type] = listeners[type] || [];

		// si no existen eventos, adjunte el oyente
		if (!typeListeners.length) {
			target.attachEvent("on" + type, typeListeners.event = function (event) {
				var documentElement = target.document && target.document.documentElement || target.documentElement || { scrollLeft: 0, scrollTop: 0 };

				// Propiedades y métodos de polyfill w3c
				event.currentTarget = target;
				event.pageX = event.clientX + documentElement.scrollLeft;
				event.pageY = event.clientY + documentElement.scrollTop;
				event.preventDefault = function () { event.returnValue = false };
				event.relatedTarget = event.fromElement || null;
				event.stopImmediatePropagation = function () { immediatePropagation = false; event.cancelBubble = true };
				event.stopPropagation = function () { event.cancelBubble = true };
				event.target = event.srcElement || target;
				event.timeStamp = +new Date;

				var plainEvt = {};
				for (var i in event) {
					plainEvt[i] = event[i];
				}

				// crear una lista en caché de la lista maestra de eventos (para evitar que este bucle se rompa cuando se elimina un evento)
				for (var i = 0, typeListenersCache = [].concat(typeListeners), typeListenerCache, immediatePropagation = true; immediatePropagation && (typeListenerCache = typeListenersCache[i]); ++i) {
					// check to see if the cached event still exists in the master events list
					for (var ii = 0, typeListener; typeListener = typeListeners[ii]; ++ii) {
						if (typeListener == typeListenerCache) {
							typeListener.call(target, plainEvt);

							break;
						}
					}
				}
			});
		}

		// agregar el evento a la lista maestra de eventos
		typeListeners.push(listener);
	});

	// remover
	addToPrototype("removeEventListener", function (type, listener) {
		var
		target = this,
		listeners = target.addEventListener.listeners = target.addEventListener.listeners || {},
		typeListeners = listeners[type] = listeners[type] || [];

		// eliminar el evento coincidente más reciente de la lista maestra de eventos
		for (var i = typeListeners.length - 1, typeListener; typeListener = typeListeners[i]; --i) {
			if (typeListener == listener) {
				typeListeners.splice(i, 1);

				break;
			}
		}

		// si no existen eventos, desconecte el oyente
		if (!typeListeners.length && typeListeners.event) {
			target.detachEvent("on" + type, typeListeners.event);
		}
	});

	// enviar
	addToPrototype("dispatchEvent", function (eventObject) {
		var
		target = this,
		type = eventObject.type,
		listeners = target.addEventListener.listeners = target.addEventListener.listeners || {},
		typeListeners = listeners[type] = listeners[type] || [];

		try {
			return target.fireEvent("on" + type, eventObject);
		} catch (error) {
			if (typeListeners.event) {
				typeListeners.event(eventObject);
			}

			return;
		}
	});

	// CustomEvent
	Object.defineProperty(Window.prototype, "CustomEvent", {
		get: function () {
			var self = this;

			return function CustomEvent(type, eventInitDict) {
				var event = self.document.createEventObject(), key;

				event.type = type;
				for (key in eventInitDict) {
					if (key == 'cancelable'){
						event.returnValue = !eventInitDict.cancelable;
					} else if (key == 'bubbles'){
						event.cancelBubble = !eventInitDict.bubbles;
					} else if (key == 'detail'){
						event.detail = eventInitDict.detail;
					}
				}
				return event;
			};
		}
	});

	// ready
	function ready(event) {
		if (ready.interval && document.body) {
			ready.interval = clearInterval(ready.interval);

			document.dispatchEvent(new CustomEvent("DOMContentLoaded"));
		}
	}

	ready.interval = setInterval(ready, 1);

	window.addEventListener("load", ready);
})();

(!this.CustomEvent || typeof this.CustomEvent === "object") && (function() {
	// CustomEvent para navegadores que no admiten de forma nativa el método Constructor
	this.CustomEvent = function CustomEvent(type, eventInitDict) {
		var event;
		eventInitDict = eventInitDict || {bubbles: false, cancelable: false, detail: undefined};

		try {
			event = document.createEvent('CustomEvent');
			event.initCustomEvent(type, eventInitDict.bubbles, eventInitDict.cancelable, eventInitDict.detail);
		} catch (error) {
			// para los navegadores que no son compatibles con CustomEvent, usamos un evento regular en su lugar
			event = document.createEvent('Event');
			event.initEvent(type, eventInitDict.bubbles, eventInitDict.cancelable);
			event.detail = eventInitDict.detail;
		}

		return event;
	};
})();

Que te diviertas ❤️!


Interesado en la programación desde los 14 años, Carlos es un programador autodidacta, fundador y autor de la mayoría de los artículos de Our Code World.

Conviertete en un programador más sociable

Patrocinadores