Jak przekazać zdarzenie jako argument do wbudowanej obsługi zdarzeń w JavaScript?

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

Zadano kilka podobnych pytań.

Ale w moim kodzie próbuję uzyskać elementy podrzędne, które zostały kliknięte, takie jak alubspan .

Jaki jest więc prawidłowy sposób przekazywania eventjako argumentu do programu obsługi zdarzeń lub jak uzyskać zdarzenie wewnątrz modułu obsługi bez przekazywania argumentu?

edytować

Jestem tego świadomy addEventListeneri jQueryproszę o podanie rozwiązania umożliwiającego przekazanie inlinezdarzenia osobie obsługującej wydarzenie.

user1643156
źródło
5
Czy istnieje dobry powód, aby używać wbudowanych programów obsługi zdarzeń zamiast przełączać się na addEventListener? en.wikipedia.org/wiki/Unobtrusive_JavaScript
Xotic750
2
@ Xotic750 Dla mnie tak, nie muszę przejmować się ponownym wiązaniem ich ręcznie za każdym razem, gdy dynamicznie ładuje się lub przeładowuje html na przykład przez Ajax.
Wadih M.

Odpowiedzi:

173

przekazać eventobiekt:

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

aby uzyskać kliknięte dziecko element(należy użyć z eventparametrem:

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

przekazać elementsiebie (DOMElement):

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

zobacz przykład na żywo na jsFiddle

Akram Berkawy
źródło
11
(A dla każdego, kto się zastanawia: tak, to działa w Chrome, Firefox itp., Nawet jeśli niektóre [na przykład Firefox] nie mają eventobiektu globalnego . Dzieje się tak, ponieważ kontekst, w którym wywoływana jest procedura obsługi DOM0, ma eventobiekt , nawet jeśli [w niektórych przeglądarkach] nie jest globalny.)
TJ Crowder
thisodnosi się do p, ale próbuję uzyskać alubspan
user1643156
3
Przechodzenie przez „zdarzenie” to jedyny znany mi sposób, pod warunkiem, że jest obsługiwany. Analiza „tego” nie przydaje się w tej sytuacji
Xotic750
5
@ user1643156 To bardzo ważne. parametr musi mieć dokładnie taką nazwę, jak „zdarzenie”
Wskaźnik zerowy -
1
Odpowiedź Wadiha M. jest o wiele lepsza niż ta. Ten jest mylący (podobnie jak inne podobne do niego), powodując, że ludzie uważają, że parametr „(event)” powinien być umieszczony w wywołaniu funkcji, podczas gdy w rzeczywistości JavaScript ma już parametr „event” i jest łatwo dostępny w wywołanej funkcji, więc nie ma potrzeby jej deklarować (zajęło mi kilka dni, zanim zdałem sobie sprawę, że zmiana nazwy zmiennej nie ma znaczenia, ponieważ tak naprawdę nie była przekazywana). Ponadto podane tam wyjaśnienie odrzuca wszelkie wątpliwości, dlaczego JS działa w ten sposób (może nie powinien, ale to nie do mnie należy osądzać ...)
Cyberknight
17

Ponieważ zdarzenia inline są wykonywane jako funkcje, możesz po prostu użyć argumentów .

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

i

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

„Zdarzenie”, o którym mowa w zaakceptowanej odpowiedzi, jest w rzeczywistości nazwą argumentu przekazanego do funkcji. Nie ma to nic wspólnego z wydarzeniem globalnym.

Semra
źródło
Dobra wskazówka. Kiedy ludzie zaczną wdrażać komponenty internetowe call()i apply()okażą się niezbędni w emulowaniu możliwości wiązania danych dostępnych w głównych frameworkach js. Dodatkową sztuczką jest zrobienie czegoś podobnego do Object.assign(this.querySelector('my-btn'), this)wewnątrz komponentu WWW i voila, powiązanie danych. Możesz uzyskać dostęp do dowolnej metody nadrzędnej klasy komponentu WWW ze zdarzeń wbudowanych onclick="toggleBtnActive.call(this, true)".
Adrian Moisa
9

Nie musisz przekazywać this, istnieje już eventobiekt przekazywany domyślnie automatycznie, który zawieraevent.target obiekt, z którego pochodzi. Możesz rozjaśnić swoją składnię:

To:

<p onclick="doSomething()">

Będzie działać z tym:

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

Nie musisz tworzyć instancji eventobiektu, on już tam jest. Wypróbuj to. Ievent.target będzie zawierał cały obiekt, który go wywołuje, do którego wcześniej odwoływałeś się jako „this”.

Teraz, jeśli dynamicznie uruchomisz metodę doSomething () z dowolnego miejsca w kodzie, zauważysz, że eventjest to niezdefiniowane. Dzieje się tak, ponieważ nie został wywołany przez kliknięcie. Jeśli więc nadal chcesz sztucznie wywołać zdarzenie, po prostu użyj dispatchEvent:

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

Wtedy doSomething()zobaczy eventievent.target jak zwykle!

Nie ma potrzeby przechodzenia thiswszędzie, a sygnatury funkcji mogą być wolne od informacji o okablowaniu i upraszczać.

Wadih M.
źródło
Przynajmniej w IE11 to nieprawda, nie ma domyślnych argumentów.
cskwg
1
@cskwg Działa również z IE11. Działa we wszystkich głównych przeglądarkach, ponieważ jest to konieczne dla kompatybilności wstecznej. Jak wspomniałem w odpowiedzi, tylko jeśli funkcja javascript jest uruchamiana ze zdarzenia, co jest jedynym scenariuszem, w którym zdarzenie istnieje, będzie istniał obiekt o nazwie „zdarzenie”, do którego można łatwo uzyskać dostęp w swojej funkcji bez konieczności przekazać dodatkowe okablowanie do prototypu funkcji. Właśnie wykonałem test na moim komputerze z IE11 dla zdarzenia onclick, a zmienna „event” zawierała „obiekt PointerEvent”.
Wadih M.