Penangan peristiwa JavaScript dengan parameter

91

Saya ingin membuat eventHandler yang meneruskan event dan beberapa parameter. Masalahnya adalah fungsinya tidak mendapatkan elemen. Berikut ini contohnya:

doClick = function(func){
    var elem = .. // the element where it is all about
    elem.onclick = function(e){
        func(e, elem);
    }
}
doClick(function(e, element){
    // do stuff with element and the event
});

'Elem' harus ditentukan di luar fungsi anonim. Bagaimana saya bisa mendapatkan elemen yang diteruskan untuk digunakan dalam fungsi anonim? Apakah ada cara untuk melakukan ini?

Dan bagaimana dengan addEventListener? Saya sepertinya tidak bisa melewatkan acara melalui addEventListener sama sekali, bukan?

Memperbarui

Sepertinya saya memperbaiki masalah dengan 'ini'

doClick = function(func){
    var that = this;
    this.element.onclick = function(e){
        func(e, that);
    }
}

Dimana ini berisi this.element yang bisa saya akses dalam fungsinya.

AddEventListener

Tapi saya bertanya-tanya tentang addEventListener:

function doClick(elem, func){
    element.addEventListener('click', func(event, elem), false);
}
sebas2day
sumber
2
Anda memiliki elem, elemen, elemen yang terlibat dalam pertanyaan Anda. Bisakah Anda mengurangi kebingungan?
mihai
Maaf, saya mencoba membuat contoh situasi saya tetapi ini tidak berjalan dengan baik, saya memperbarui kodenya.
sebas2day
Apakah Anda mencari e.target/ e.currentTarget?
Rolf
1
cara mengirim parameter jika im menggunakan ini: ok.addEventListener ("click", this.changeText.bind (this));
Alberto Acuña

Jawaban:

103

Saya tidak mengerti persis apa yang coba dilakukan kode Anda, tetapi Anda dapat membuat variabel tersedia di semua event handler menggunakan keuntungan dari penutupan fungsi:

function addClickHandler(elem, arg1, arg2) {
    elem.addEventListener('click', function(e) {
        // in the event handler function here, you can directly refer
        // to arg1 and arg2 from the parent function arguments
    }, false);
}

Bergantung pada situasi pengkodean Anda yang tepat, Anda selalu dapat membuat semacam penutupan untuk mempertahankan akses ke variabel untuk Anda.

Dari komentar Anda, jika yang ingin Anda capai adalah ini:

element.addEventListener('click', func(event, this.elements[i]))

Kemudian, Anda dapat melakukan ini dengan fungsi eksekusi mandiri (IIFE) yang menangkap argumen yang Anda inginkan dalam closure saat ia mengeksekusi dan mengembalikan fungsi penanganan kejadian yang sebenarnya:

element.addEventListener('click', (function(passedInElement) {
    return function(e) {func(e, passedInElement); };
}) (this.elements[i]), false);

Untuk info lebih lanjut tentang cara kerja IIFE, lihat referensi lain ini:

Kode pembungkus Javascript di dalam fungsi anonim

Ekspresi Fungsi (IIFE) yang Segera Diminta Dalam JavaScript - Meneruskan jQuery

Apa kasus penggunaan yang baik untuk JavaScript yang menjalankan sendiri fungsi anonim?

Versi terakhir ini mungkin lebih mudah untuk melihat apa yang dilakukannya seperti ini:

// return our event handler while capturing an argument in the closure
function handleEvent(passedInElement) {
    return function(e) {
        func(e, passedInElement); 
    };
}

element.addEventListener('click', handleEvent(this.elements[i]));

Bisa juga digunakan .bind()untuk menambahkan argumen ke callback. Argumen apa pun yang Anda teruskan .bind()akan ditambahkan ke argumen yang akan dimiliki oleh callback itu sendiri. Jadi, Anda bisa melakukan ini:

elem.addEventListener('click', function(a1, a2, e) {
    // inside the event handler, you have access to both your arguments
    // and the event object that the event handler passes
}.bind(elem, arg1, arg2));
jfriend00
sumber
ya ini hampir apa yang saya coba lakukan, tetapi bagaimana jika fungsi anonim dilewatkan sebagai parameter oleh addClickHandler dan Anda ingin memberikan fungsi ini beberapa parameter dengan acara seperti: element.addEventListener ('click', func (event, this.elements [i]));
sebas2day
5
@ sebas2day - Anda tidak dapat melakukannya element.addEventListener('click', func(event, this.elements[i])). Javascript tidak berfungsi seperti itu. Ada cara lain untuk menyiasatinya, menggunakan closure, tetapi Anda tidak bisa melakukannya seperti yang Anda tulis. addEventListener memanggil callbacknya dengan tepat satu argumen (peristiwa) dan Anda tidak dapat mengubahnya dengan cara apa pun.
jfriend00
Saya menambahkan contoh lain untuk melakukan ini di akhir jawaban saya.
jfriend00
@ jfriend00 Apa yang dapat Anda lakukan adalah menggunakan metode mengikat. function eventFunction (arg, evt) { console.log(arg[0],arg[1],arg[2]) console.log(evt) } var el = document.getElementById('elementID'); el.addEventListener('click', eventFunction.bind(el,[1,2,3])) Perhatikan bahwa argumen event selalu terakhir dalam argumen untuk fungsi tersebut, dan tidak secara eksplisit dideklarasikan dalam metode bind.
Knight Yoshi
2
@ Bosh19 - lihat apa yang telah saya tambahkan di akhir jawaban saya untuk menjelaskan konstruksi yang Anda tanyakan. Ini adalah ekspresi fungsi yang segera dipanggil (IIFE) yang pada dasarnya merupakan fungsi yang dideklarasikan secara anonim yang segera dieksekusi. Ini adalah jalan pintas untuk mendefinisikan suatu fungsi dan kemudian memanggilnya - berguna ketika Anda menginginkan badan sebaris dan itu tidak akan dipanggil di mana pun sehingga tidak memerlukan nama.
jfriend00
29

Ini adalah pertanyaan lama tapi pertanyaan umum. Jadi izinkan saya menambahkan yang ini di sini.

Dengan sintaks fungsi panah Anda dapat mencapainya dengan cara yang lebih ringkas karena secara leksikal terikat dan dapat dirantai.

Ekspresi fungsi panah adalah alternatif yang secara sintaksis ringkas untuk ekspresi fungsi reguler, meskipun tanpa ikatannya sendiri ke kata kunci this, arguments, super, atau new.target.

const event_handler = (event, arg) => console.log(event, arg);
el.addEventListener('click', (event) => event_handler(event, 'An argument'));

Jika Anda perlu membersihkan pendengar acara:

// Let's use use good old function sytax
function event_handler(event, arg) {
  console.log(event, arg);
}

// Assign the listener callback to a variable
var doClick = (event) => event_handler(event, 'An argument'); 

el.addEventListener('click', doClick);

// Do some work...

// Then later in the code, clean up
el.removeEventListener('click', doClick);

Ini satu kalimat gila:

// You can replace console.log with some other callback function
el.addEventListener('click', (event) => ((arg) => console.log(event, arg))('An argument'));

Versi yang lebih jinak : Lebih sesuai untuk pekerjaan yang waras.

el.addEventListener('click', (event) => ((arg) => {
  console.log(event, arg);
})('An argument'));
snnsnn
sumber
2
Ini sepertinya solusi yang masuk akal, tetapi bagaimana dengan saat Anda harus menghapus event listener yang sama?
Dushyant Sabharwal
@SnnSnn: +1. Saya menggunakan ini untuk menyediakan properti kelas ke event handler. Saya baru saja masuk thisdan pawang dapat mengakses apa yang dibutuhkannya.
Robotron
1
Jika pemahaman saya benar, Anda sebenarnya akan meneruskan fungsi anonim sebagai pengendali event Anda: (e) => {....} dan bukan yourEventHandlerFunction (). Ini akan menyebabkan masalah jika Anda ingin menghapus event handler nanti, karena Anda meneruskan fungsi anonim untuk memulai ???
PowerAktar
Answer dengan jelas menjelaskan cara menghapus event listener, jadi tidak ada masalah.
snnsnn
9

Sesuatu yang dapat Anda coba adalah menggunakan metode mengikat, saya pikir ini mencapai apa yang Anda minta. Jika tidak ada yang lain, itu masih sangat berguna.

function doClick(elem, func) {
  var diffElem = document.getElementById('some_element'); //could be the same or different element than the element in the doClick argument
  diffElem.addEventListener('click', func.bind(diffElem, elem))
}

function clickEvent(elem, evt) {
  console.log(this);
  console.log(elem); 
  // 'this' and elem can be the same thing if the first parameter 
  // of the bind method is the element the event is being attached to from the argument passed to doClick
  console.log(evt);
}

var elem = document.getElementById('elem_to_do_stuff_with');
doClick(elem, clickEvent);
Knight Yoshi
sumber
2

Mengingat pembaruan untuk pertanyaan asli, sepertinya ada masalah dengan konteks ("ini") saat melewati penangan kejadian. Dasar-dasarnya dijelaskan misalnya di sini http://www.w3schools.com/js/js_function_invocation.asp

Versi kerja sederhana dari contoh Anda bisa dibaca

var doClick = function(event, additionalParameter){
    // do stuff with event and this being the triggering event and caller
}

element.addEventListener('click', function(event)
{
  var additionalParameter = ...;
  doClick.call(this, event, additionalParameter );
}, false);

Lihat juga Javascript call () & apply () vs bind ()?

Echsecutor
sumber
1

Jawaban singkat:

x.addEventListener("click", function(e){myfunction(e, param1, param2)});

... 

function myfunction(e, param1, param1) {
    ... 
} 
pengguna3093134
sumber
1
Ini tidak bekerja dengan benar. Jika nilai parameter Anda berubah setiap kali pengendali kejadian disetel, ini akan menghasilkan hasil yang tidak diharapkan karena tidak mendekati nilai param1atau param2. Jika nilai-nilai itu berubah, mereka tidak akan disetel ke nilai yang semula saat pengendali kejadian dibuat. Mereka akan disetel ke nilai saat ini saja. Selain itu, ini tidak berbeda dengan menyetel variabel di luar cakupan fungsi event listener dan mereferensikan variabel tersebut di event handler, sehingga tidak menyelesaikan penerusan parameter sama sekali.
TetraDev
Saya tidak benar-benar mengerti maksud Anda sehingga tanggapan saya mungkin tidak tepat. Bagaimanapun, event handler diatur sekali (tidak selalu saya kira tapi biasanya itulah yang diinginkan seseorang). Kedua, ini cukup banyak mengatakan bahwa fungsi handler adalah fungsi saya dan memiliki 2 parameter ditambah variabel "event". Ketiga, ya itu berhasil dan hasilnya persis seperti yang diharapkan.
pengguna3093134
1
Tidak, itu tidak berhasil. Saya mengujinya persis seperti yang Anda lakukan dan poin saya tetap valid. Jika param1adalah noodlepertama kalinya addEventListener disebut, dan kedua kalinya Anda menyebutnya, paramadalah cheesemaka kapan saja pendengar acara clickkebakaran, param1akan diatur ke cheesedan tidak noodle. Oleh karena itu, ia tidak menggunakan "closure" untuk mengingat nilai yang ada pada saat event listener ditambahkan. Ada skenario di mana pendengar acara harus ditambahkan beberapa kali yang tidak perlu diilustrasikan agar poin saya valid.
TetraDev
Saya bukan seorang ahli dan saya belum pernah mendengar tentang "penutupan" dalam pemrograman sebelumnya, jadi saya tidak mengerti apa yang Anda maksud dengan itu.
pengguna3093134
2
Terima kasih telah memeriksanya, saya pasti akan mengunjungi tautan yang Anda posting, juga. Juga, saya harus mengatakan Anda sangat sopan dan jujur ​​Pak, teruskan dan semoga harimu menyenangkan :)
user3093134
0

thisdi dalam doThingsadalah objek jendela. Coba ini sebagai gantinya:

var doThings = function (element) {
    var eventHandler = function(ev, func){
        if (element[ev] == undefined) {
            return;
        }

        element[ev] = function(e){
            func(e, element);
        }
    };

    return {
        eventHandler: eventHandler
    };
};
jbabey.dll
sumber
-2
let obj = MyObject();

elem.someEvent( function(){ obj.func(param) } );

//calls the MyObject.func, passing the param.
Δημήτρης Βουζουναράς
sumber
param bisa juga merupakan fungsi panggilan balik (dalam konteks -say- global) dan bisa dengan mudah dipanggil kembali, dengan parameter yang diminta.
Δημήτρης Βουζουναράς