Як передати подію як аргумент вбудованому обробнику подій у 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>

Є кілька подібних питань.

Але у своєму коді я намагаюся отримати дочірні елементи, на яких клацнули, наприклад aабоspan .

Отже, який правильний спосіб передавати eventяк аргумент обробнику подій, або як отримати подію всередині обробника без передачі аргументу?

редагувати

Мені відомо, addEventListenerі jQuery, будь ласка, надайте рішення для передачі події до передавача подій inline.



5
Чи є поважна причина для використання вбудованих обробників подій, а не для переходу на addEventListener? en.wikipedia.org/wiki/Unobtrusive_JavaScript
Xotic750

2
@ Xotic750 Для мене так, не потрібно дбати про те, щоб перев’язувати їх вручну щоразу при динамічному завантаженні або перезавантаженні html через ajax, наприклад.
Вадіх М.,

Відповіді:


166

для передачі 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

3
Проходження «події» - це єдиний спосіб, який я знаю, якщо він підтримується. Розбір "цього" в цій ситуації не
принесе користі

5
@ user1643156 Це дуже важливо. параметр повинен бути названий точно як "подія"
The-null-Pointer -

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)".
Adrian Moisa

8

Вам не потрібно передавати this, там вже є eventоб’єкт, переданий за замовчуванням автоматично, який містить event.targetоб’єкт, з якого він походить. Ви можете полегшити свій синтаксис:

Це:

<p onclick="doSomething()">

Буде працювати з цим:

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

Вам не потрібно створювати екземпляр eventоб’єкта, він уже там. Спробуй. Іevent.target міститиме весь об’єкт, який його викликає, і який ви раніше називали "цим".

Тепер, якщо ви динамічно запускаєте doSomething () десь у вашому коді, ви помітите, що eventце невизначено. Це пов’язано з тим, що це не було викликано подією клацання. Отже, якщо ви все-таки хочете штучно викликати подію, просто використовуйте 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".
Вадіх М.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.