Как передать событие в качестве аргумента встроенному обработчику событий в JavaScript?

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

Было задано несколько подобных вопросов.

Но в моем коде я пытаюсь получить дочерние элементы, на которые нажимали, например aилиspan .

Итак, как правильно передать eventв качестве аргумента обработчик событий или как получить событие внутри обработчика без передачи аргумента?

редактировать

Я знаю об этом addEventListenerи jQuery, пожалуйста, предоставьте решение для передачи inlineсобытия обработчику события.

user1643156
источник
5
Есть ли веская причина использовать встроенные обработчики событий вместо перехода на addEventListener? en.wikipedia.org/wiki/Unobtrusive_JavaScript
Xotic750,
2
@ Xotic750 Для меня да, нет необходимости каждый раз заново связывать их вручную, например, при динамической загрузке или перезагрузке html через ajax.
Вадих М.

Ответы:

167

передать eventобъект:

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

чтобы получить дочерний elementэлемент, по которому щелкнули (следует использовать с eventпараметром:

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

передать elementсам (DOMElement):

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

см. живой пример на jsFiddle

Акрам Беркави
источник
11
(И для тех, кому интересно: да, это работает в Chrome, Firefox и т. Д., Хотя некоторые [Firefox, например] не имеют глобального eventобъекта. Это потому, что контекст, в котором вызывается обработчик DOM0, имеет eventобъект , даже если [в некоторых браузерах] это не глобально.)
TJ Crowder
thisотносится p, но я пытаюсь получить aилиspan
user1643156 06
3
Прохождение «события» - единственный известный мне способ, при условии, что он поддерживается. Парсить «это» в данной ситуации
бесполезно
5
@ user1643156 Это очень важно. параметр должен называться точно так же, как "событие"
нулевой указатель -
1
Ответ Вадих М. намного лучше этого. Этот вводит в заблуждение (как и другие подобные ему), заставляя людей поверить, что параметр «(событие)» должен быть помещен в вызов функции, тогда как на самом деле в JavaScript уже есть параметр «событие», который легко доступен внутри вызываемой функции, поэтому нет необходимости объявлять ее (мне потребовалось несколько дней, чтобы понять, что изменение имени переменной не имеет значения, потому что на самом деле оно не передавалось). Кроме того, приведенное там объяснение развеивает любые сомнения относительно того, почему JS работает именно так (возможно, и не должно, но это не мне судить ...)
Cyberknight
15

Поскольку встроенные события выполняются как функции, вы можете просто использовать аргументы .

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

и

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

«Событие», упомянутое в принятом ответе, на самом деле является именем аргумента, переданного функции. Это не имеет ничего общего с глобальным событием.

Семра
источник
Хороший совет. Когда люди начнут внедрять веб-компоненты call()и apply()окажутся необходимыми для имитации возможностей привязки данных, доступных в основных js-фреймворках. Еще одна уловка - сделать что-то подобное Object.assign(this.querySelector('my-btn'), this)внутри веб-компонента и вуаля, привязка данных. Вы можете получить доступ к любому методу родительского класса веб-компонента из встроенных событий onclick="toggleBtnActive.call(this, true)".
Адриан Мойса
8

Вам не нужно передавать this, уже есть eventобъект, переданный по умолчанию автоматически, который содержит event.targetобъект, из которого он исходит. Вы можете облегчить свой синтаксис:

Это:

<p onclick="doSomething()">

Будет работать с этим:

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

Вам не нужно создавать экземпляр event объекта, он уже существует. Попробуйте сами. И event.targetбудет содержать весь вызывающий его объект, на который вы раньше ссылались как на «это».

Теперь, если вы динамически запускаете doSomething () откуда-то в своем коде, вы заметите, что eventэто undefined. Это потому, что он не был вызван событием щелчка. Поэтому, если вы все еще хотите искусственно вызвать событие, просто используйте dispatchEvent:

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

Тогда doSomething()увидимevent и event.targetкак обычно!

Нет необходимости проходить thisвезде, и вы можете избавить свои сигнатуры функций от информации о связях и упростить вещи.

Вадих М.
источник
По крайней мере, в IE11 это не так, аргументов по умолчанию нет.
cskwg
1
@cskwg Это работает и для IE11. Он работает во всех основных браузерах, так как это необходимо для обратной совместимости. Как я уже упоминал в ответе, только если функция javascript запускается из события, что является единственным сценарием, в котором событие существует, будет объект, уже называемый «событием», к которому вы можете легко получить доступ внутри своей функции без необходимости передайте дополнительную проводку вашему прототипу функции. Я только что провел тест на своем компьютере с IE11 для события onclick, и переменная 'event' содержала «объект PointerEvent».
Вадих М.