Bagaimana cara melewatkan acara sebagai argumen ke penangan kejadian sebaris di 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>

Ada beberapa pertanyaan serupa yang telah ditanyakan.

Namun dalam kode saya, saya mencoba mendapatkan elemen anak yang telah diklik, suka aatauspan .

Jadi, apa cara yang benar untuk mengirimkan eventsebagai argumen ke pengendali kejadian, atau bagaimana cara memasukkan kejadian ke dalam pengendali tanpa memberikan argumen?

edit

Saya mengetahui addEventListenerdan jQuery, berikan solusi untuk meneruskan acara ke inlinepenangan acara.

pengguna1643156
sumber
5
Apakah ada alasan bagus untuk menggunakan penangan kejadian sebaris daripada beralih ke addEventListener? en.wikipedia.org/wiki/Unobtrusive_JavaScript
Xotic750
2
@ Xotic750 Bagi saya ya, tidak perlu peduli tentang mengikat ulang secara manual setiap kali saat memuat atau memuat ulang html secara dinamis melalui ajax misalnya.
Wadih M.

Jawaban:

167

untuk melewati eventobjek:

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

untuk mendapatkan turunan yang diklik element(harus digunakan dengan eventparameter:

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

untuk lulus elementsendiri (DOMElement):

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

lihat contoh langsung di jsFiddle

Akram Berkawy
sumber
11
(Dan bagi siapa pun yang bertanya-tanya: Ya, ini berfungsi di Chrome, Firefox, dll., Meskipun beberapa [Firefox, misalnya] tidak memiliki eventobjek global . Itu karena konteks di mana handler DOM0 dipanggil memiliki eventobjek , meskipun [pada beberapa browser] ini bukan global.)
TJ Crowder
thismengacu pada p, tapi saya mencoba untuk mendapatkan aatauspan
user1643156
3
Melewati 'acara' adalah satu-satunya cara yang saya tahu, asalkan didukung. Parsing ´this´ tidak berguna dalam situasi ini
Xotic750
5
@ user1643156 Itu sangat penting. parameter harus dinamai persis seperti "event"
The-null-Pointer-
1
Jawaban Wadih M. jauh lebih baik dari ini. Yang ini menyesatkan (seperti orang lain yang serupa dengannya), membuat orang percaya bahwa parameter "(event)" harus dimasukkan ke dalam pemanggilan fungsi, padahal sebenarnya JavaScript telah memiliki parameter "event" dan tersedia di dalam fungsi yang dipanggil, jadi tidak perlu mendeklarasikannya (saya butuh waktu berhari-hari untuk menyadari bahwa tidak ada bedanya mengubah nama variabel, karena tidak benar-benar disahkan). Juga, penjelasan yang diberikan di sana menghilangkan keraguan tentang mengapa JS bekerja seperti itu (mungkin seharusnya tidak, tapi itu bukan hak saya untuk menilai ...)
Cyberknight
15

Karena kejadian sebaris dijalankan sebagai fungsi, Anda cukup menggunakan argumen .

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

dan

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

'Peristiwa' yang disebutkan dalam jawaban yang diterima sebenarnya adalah nama argumen yang diteruskan ke fungsi tersebut. Ini tidak ada hubungannya dengan acara global.

Semra
sumber
Tip bagus. Ketika orang-orang akan mulai mengadopsi komponen web call()dan apply()akan terbukti penting dalam meniru kemampuan pengikatan data yang tersedia dalam kerangka js arus utama. Satu trik tambahan adalah melakukan sesuatu yang mirip dengan Object.assign(this.querySelector('my-btn'), this)di dalam komponen web dan voila, data binding. Anda dapat mengakses metode apa pun dari kelas komponen web induk dari acara inline onclick="toggleBtnActive.call(this, true)".
Adrian Moisa
8

Anda tidak perlu melewatkan this, sudah ada eventobjek yang diteruskan secara otomatis secara default, yang berisi dari event.targetmana objek asalnya. Anda dapat meringankan sintaks Anda:

Ini:

<p onclick="doSomething()">

Akan bekerja dengan ini:

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

Anda tidak perlu membuat instance eventobjek, itu sudah ada. Cobalah. Dan event.targetakan berisi seluruh objek yang memanggilnya, yang sebelumnya Anda rujuk sebagai "ini".

Sekarang jika Anda secara dinamis memicu doSomething () dari suatu tempat di kode Anda, Anda akan melihat bahwa eventtidak ditentukan. Ini karena tidak dipicu dari peristiwa mengklik. Jadi jika Anda masih ingin memicu peristiwa secara artifisial, cukup gunakan dispatchEvent:

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

Kemudian doSomething()akan melihat eventdan event.targetseperti biasa!

Tidak perlu melewati thiskemana - mana, dan Anda dapat menjaga agar tanda tangan fungsi Anda bebas dari informasi kabel dan menyederhanakan banyak hal.

Wadih M.
sumber
Setidaknya di IE11, ini tidak benar, Tidak ada argumen default.
cskwg
1
@cskwg Ini berfungsi untuk IE11 juga. Ini berfungsi di semua browser utama karena ini diperlukan untuk kompatibilitas ke belakang. Seperti yang saya sebutkan di jawaban, hanya jika fungsi javascript diaktifkan dari suatu peristiwa, yang merupakan satu-satunya skenario di mana suatu peristiwa ada, akan ada objek yang sudah disebut "peristiwa" yang dapat Anda akses dengan mudah di dalam fungsi Anda tanpa harus berikan kabel ekstra ke prototipe fungsi Anda. Saya baru saja melakukan tes pada mesin saya dengan IE11 untuk event onclick dan variabel 'event' berisi "objek PointerEvent".
Wadih M.