Comment passer un événement en tant qu'argument à un gestionnaire d'événements en ligne 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>

Des questions similaires ont été posées.

Mais dans mon code, j'essaye d'obtenir des éléments enfants sur lesquels on a cliqué, comme aouspan .

Alors, quelle est la bonne façon de passer eventcomme argument au gestionnaire d'événements, ou comment obtenir un événement à l'intérieur du gestionnaire sans passer d'argument?

Éditer

Je suis au courant addEventListeneret jQuery, veuillez fournir une solution pour passer un événement à un organisateur d' inlineévénements.

user1643156
la source
5
Y a-t-il une bonne raison d'utiliser des gestionnaires d'événements en ligne plutôt que de passer à addEventListener? en.wikipedia.org/wiki/Unobtrusive_JavaScript
Xotic750
2
@ Xotic750 Pour moi oui, pas besoin de se soucier de les relier manuellement à chaque fois lors du chargement ou du rechargement dynamique du HTML via ajax par exemple.
Wadih M.

Réponses:

166

pour passer l' eventobjet:

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

pour obtenir l'enfant cliqué element(doit être utilisé avec le eventparamètre:

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

pour passer le elementlui - même (DOMElement):

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

voir l'exemple en direct sur jsFiddle

Akram Berkawy
la source
11
(Et pour ceux qui se demandent: oui, cela fonctionne sur Chrome, Firefox, etc., même si certains [Firefox, par exemple] n'ont pas d' eventobjet global . C'est parce que le contexte dans lequel le gestionnaire DOM0 est appelé a un eventobjet , même si [sur certains navigateurs] ce n'est pas un global.)
TJ Crowder
thisfait référence à p, mais j'essaie d'obtenir aouspan
user1643156
3
Passer «événement» est le seul moyen que je connaisse, à condition qu'il soit soutenu. L'analyse «ceci» n'est d'aucune utilité dans cette situation
Xotic750
5
@ user1643156 C'est très important. le paramètre doit être nommé exactement comme "événement"
The-null-Pointer-
1
La réponse de Wadih M. est bien meilleure que cela. Celui-ci est trompeur (comme d'autres similaires), faisant croire aux gens que le paramètre "(event)" devrait être mis dans l'appel de fonction, alors qu'en fait, JavaScript a déjà le paramètre "event" et facilement disponible dans la fonction appelée, il n'y a donc pas besoin de le déclarer (il m'a fallu des jours pour me rendre compte qu'il n'y avait aucune différence en changeant le nom de la variable, car il n'était pas vraiment passé). De plus, l'explication qui y est donnée rejette tout doute sur la raison pour laquelle JS fonctionne comme ça (peut-être que cela ne devrait pas, mais ce n'est pas à moi de juger ...)
Cyberknight
15

Puisque les événements en ligne sont exécutés comme des fonctions, vous pouvez simplement utiliser des arguments .

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

et

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

L '«événement» mentionné dans la réponse acceptée est en fait le nom de l'argument passé à la fonction. Cela n'a rien à voir avec l'événement mondial.

Semra
la source
Bon conseil. Quand les gens commenceront à adopter des composants Web call()et apply()se révéleront essentiels pour émuler les capacités de liaison de données disponibles dans les frameworks js traditionnels. Une astuce supplémentaire consiste à faire quelque chose de similaire à l' Object.assign(this.querySelector('my-btn'), this)intérieur d'un composant Web et voila, la liaison de données. Vous pouvez accéder à n'importe quelle méthode de la classe de composant Web parent à partir des événements en ligne onclick="toggleBtnActive.call(this, true)".
Adrian Moisa
8

Vous n'avez pas besoin de passer this, il y a déjà l' eventobjet passé par défaut automatiquement, qui contient de event.targetquel objet il provient. Vous pouvez alléger votre syntaxe:

Ce:

<p onclick="doSomething()">

Fonctionnera avec ceci:

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

Vous n'avez pas besoin d'instancier l' eventobjet, il est déjà là. Essaye le. Et event.targetcontiendra l'objet entier l'appelant, auquel vous faisiez référence auparavant comme "ceci".

Maintenant, si vous déclenchez dynamiquement doSomething () à partir de quelque part dans votre code, vous remarquerez que ce eventn'est pas défini. C'est parce qu'il n'a pas été déclenché par un événement de clic. Donc, si vous souhaitez toujours déclencher artificiellement l'événement, utilisez simplement dispatchEvent:

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

Puis doSomething()verra eventet event.targetcomme d'habitude!

Pas besoin de passer thispartout, vous pouvez garder vos signatures de fonction exemptes d'informations de câblage et simplifier les choses.

Wadih M.
la source
Au moins sur IE11, ce n'est pas vrai, il n'y a pas d'arguments par défaut.
cskwg le
1
@cskwg Cela fonctionne également pour IE11. Cela fonctionne sur tous les principaux navigateurs car cela est nécessaire pour la compatibilité ascendante. Comme je l'ai mentionné dans la réponse, seulement si la fonction javascript est déclenchée à partir d'un événement, qui est le seul scénario où un événement existe, il y aura un objet déjà appelé "événement" auquel vous pourrez accéder facilement à l'intérieur de votre fonction sans avoir à le faire transmettre un câblage supplémentaire à votre prototype de fonction. Je viens de faire un test sur ma machine avec IE11 pour un événement onclick et la variable 'event' contenait un "objet PointerEvent".
Wadih M.