¿Cómo pasar un evento como argumento a un controlador de eventos en línea en JavaScript?

103
// this e works
document.getElementById("p").oncontextmenu = function(e) {
    e = e || window.event;
    var target = e.target || e.srcElement;
    console.log(target);
};

// this e is undefined
function doSomething(e) {
    e = e || window.event;
    var target = e.target || e.srcElement;
    console.log(target);
}
<p id="p" onclick="doSomething(e)">
    <a href="#">foo</a>
    <span>bar</span>
</p>

Se han hecho algunas preguntas similares.

Pero en mi código, estoy tratando de obtener elementos secundarios en los que se haya hecho clic, como aospan .

Entonces, ¿cuál es la forma correcta de pasar eventcomo argumento al controlador de eventos, o cómo obtener el evento dentro del controlador sin pasar un argumento?

editar

Soy consciente de addEventListenery jQuery, por favor, proporcione una solución para pasar de un evento a otro inline.

user1643156
fuente
5
¿Existe una buena razón para usar controladores de eventos en línea en lugar de cambiar a addEventListener? en.wikipedia.org/wiki/Unobtrusive_JavaScript
Xotic750
2
@ Xotic750 Para mí, sí, no hay necesidad de preocuparse por volver a vincularlos manualmente cada vez que se cargan o recargan dinámicamente html a través de ajax, por ejemplo.
Wadih M.

Respuestas:

166

para pasar el eventobjeto:

<p id="p" onclick="doSomething(event)">

para obtener el niño en el que se hizo clic element(debe usarse con el eventparámetro:

function doSomething(e) {
    e = e || window.event;
    var target = e.target || e.srcElement;
    console.log(target);
}

para pasar el elementmismo (DOMElement):

<p id="p" onclick="doThing(this)">

ver ejemplo en vivo en jsFiddle

Akram Berkawy
fuente
11
(Y para cualquiera que se pregunte: Sí, esto funciona en Chrome, Firefox, etc., aunque algunos [Firefox, por ejemplo] no tienen un eventobjeto global . Es porque el contexto en el que se llama al controlador DOM0 tiene un eventobjeto , incluso si [en algunos navegadores] no es global.)
TJ Crowder
thishace referencia p, pero estoy tratando de obtener aospan
user1643156
3
Pasar "evento" es la única forma que conozco, siempre que sea compatible. Analizar "esto" no sirve de nada en esta situación
Xotic750
5
@ user1643156 Eso es muy importante. el parámetro debe ser nombrado exactamente como "evento"
The-null-Pointer-
1
La respuesta de Wadih M. es mucho mejor que esto. Este es engañoso (como otros similares), lo que hace que la gente crea que el parámetro "(evento)" debe colocarse en la llamada a la función, cuando, en realidad, JavaScript ya tiene el parámetro "evento" y está disponible dentro de la función llamada, por lo que no hay necesidad de declararlo (me tomó días darme cuenta de que no importaba cambiar el nombre de la variable, porque en realidad no se estaba pasando). Además, la explicación que se da allí descarta cualquier duda sobre por qué JS funciona así (tal vez no debería, pero no soy yo quien debe juzgar ...)
Cyberknight
15

Dado que los eventos en línea se ejecutan como funciones, simplemente puede usar argumentos .

<p id="p" onclick="doSomething.apply(this, arguments)">

y

function doSomething(e) {
  if (!e) e = window.event;
  // 'e' is the event.
  // 'this' is the P element
}

El 'evento' que se menciona en la respuesta aceptada es en realidad el nombre del argumento pasado a la función. No tiene nada que ver con el evento global.

Semra
fuente
Buen consejo. Cuándo las personas comenzarán a adoptar componentes web call()y apply()serán esenciales para emular las capacidades de enlace de datos disponibles en los marcos js convencionales. Un truco adicional es hacer algo similar a Object.assign(this.querySelector('my-btn'), this)dentro de un componente web y listo, enlace de datos. Puede acceder a cualquier método de la clase de componente web principal desde los eventos en línea onclick="toggleBtnActive.call(this, true)".
Adrian Moisa
8

No necesita pasar this, ya existe el eventobjeto pasado automáticamente por defecto, que contiene event.targetcuál tiene el objeto del que proviene. Puedes aligerar tu sintaxis:

Esta:

<p onclick="doSomething()">

Trabajará con esto:

function doSomething(){
  console.log(event);
  console.log(event.target);
}

No es necesario crear una instancia del eventobjeto, ya está allí. Pruébalo. Y event.targetcontendrá todo el objeto que lo llama, al que antes se refería como "esto".

Ahora, si activa dinámicamente doSomething () desde algún lugar de su código, notará que eventno está definido. Esto se debe a que no se activó por un evento de clic. Entonces, si aún desea activar artificialmente el evento, simplemente use dispatchEvent:

document.getElementById('element').dispatchEvent(new CustomEvent("click", {'bubbles': true}));

Luego doSomething()veremos eventy event.targetcomo de costumbre!

No es necesario pasar a thistodas partes, y puede mantener sus firmas de funciones libres de información de cableado y simplificar las cosas.

Wadih M.
fuente
Al menos en IE11, esto no es cierto. No hay argumentos predeterminados.
cskwg
1
@cskwg También funciona para IE11. Funciona en todos los navegadores principales, ya que es necesario para la compatibilidad con versiones anteriores. Como mencioné en la respuesta, solo si la función javascript se dispara desde un evento, que es el único escenario donde existe un evento, habrá un objeto ya llamado "evento" al que puede acceder fácilmente dentro de su función sin tener que hacerlo Pase cableado adicional a su prototipo de función. Acabo de hacer una prueba en mi máquina con IE11 para un evento onclick y la variable 'evento' contenía un "objeto PointerEvent".
Wadih M.