Trình xử lý sự kiện Javascript với các tham số


89

Tôi muốn tạo một eventHandler truyền sự kiện và một số tham số. Vấn đề là hàm không nhận được phần tử. Đây là một ví dụ:

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' phải được xác định bên ngoài chức năng ẩn danh. Làm cách nào để lấy phần tử đã qua để sử dụng trong hàm ẩn danh? Có cách nào để làm việc này không?

Còn addEventListener thì sao? Tôi dường như không thể vượt qua sự kiện thông qua addEventListener phải không?

Cập nhật

Tôi dường như đã khắc phục được sự cố với 'cái này'

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

Nơi chứa this.element mà tôi có thể truy cập trong hàm.

AddEventListener

Nhưng tôi đang thắc mắc về addEventListener:

function doClick(elem, func){
    element.addEventListener('click', func(event, elem), false);
}

2
Bạn có elem, phần tử, phần tử liên quan đến câu hỏi của bạn. Bạn có thể bớt khó hiểu hơn không?
mihai

Tôi xin lỗi, tôi đã cố gắng làm một ví dụ về tình huống của mình nhưng điều này không suôn sẻ, tôi đã cập nhật mã.
sebas2day

Bạn sẽ tìm kiếm e.target/ e.currentTarget?
Rolf

1
làm thế nào để gửi một tham số nếu tôi sử dụng this: ok.addEventListener ("click", this.changeText.bind (this));
Alberto Acuña,

Câu trả lời:


103

Tôi không hiểu chính xác mã của bạn đang cố gắng làm gì, nhưng bạn có thể cung cấp các biến trong bất kỳ trình xử lý sự kiện nào bằng cách sử dụng các ưu điểm của đóng hàm:

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);
}

Tùy thuộc vào tình huống mã hóa chính xác của bạn, bạn luôn có thể thực hiện một số loại đóng để bảo toàn quyền truy cập vào các biến cho bạn.

Từ nhận xét của bạn, nếu những gì bạn đang cố gắng hoàn thành là:

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

Sau đó, bạn có thể thực hiện việc này với một hàm tự thực thi (IIFE) nắm bắt các đối số bạn muốn trong một bao đóng khi nó thực thi và trả về hàm xử lý sự kiện thực tế:

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

Để biết thêm thông tin về cách hoạt động của IIFE, hãy xem các tài liệu tham khảo khác sau:

Mã gói Javascript bên trong hàm ẩn danh

Biểu thức hàm được gọi ngay lập tức (IIFE) Trong JavaScript - Truyền jQuery

Các trường hợp sử dụng tốt cho JavaScript tự thực thi các hàm ẩn danh là gì?

Phiên bản cuối cùng này có lẽ dễ dàng hơn để xem những gì nó đang làm như thế này:

// 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]));

Nó cũng có thể sử dụng .bind()để thêm các đối số vào một cuộc gọi lại. Bất kỳ đối số nào bạn chuyển đến .bind()sẽ được thêm vào trước các đối số mà chính lệnh gọi lại sẽ có. Vì vậy, bạn có thể làm điều này:

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));

vâng, điều này gần như là những gì tôi đang cố gắng làm, nhưng điều gì sẽ xảy ra nếu hàm ẩn danh được addClickHandler truyền làm tham số và bạn muốn cung cấp cho hàm này một số tham số với sự kiện như: element.addEventListener ('click', func (event, this.elements [i]));
thứ

5
@ sebas2day - Bạn không thể làm được element.addEventListener('click', func(event, this.elements[i])). Javascript không hoạt động theo cách đó. Có nhiều cách khác để giải quyết vấn đề đó, sử dụng các hàm đóng, nhưng bạn không thể làm theo cách bạn đã viết. addEventListener gọi nó là callback với chính xác một đối số (sự kiện) và bạn không thể thay đổi điều đó theo bất kỳ cách nào.
jfriend00

Tôi đã thêm một ví dụ khác về việc này vào cuối câu trả lời của mình.
jfriend00

@ jfriend00 Những gì bạn có thể làm là sử dụng phương thức liên kết. 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])) Lưu ý rằng đối số sự kiện luôn đứng cuối cùng trong các đối số của hàm và không được khai báo rõ ràng trong phương thức ràng buộc.
Knight Yoshi

2
@ Bosh19 - xem những gì tôi đã thêm vào cuối câu trả lời của mình để giải thích cấu trúc mà bạn đã hỏi. Đó là một biểu thức hàm được gọi ngay lập tức (IIFE) về cơ bản là một hàm được khai báo ẩn danh được thực thi ngay lập tức. Đó là một phím tắt để xác định một hàm và sau đó gọi nó - hữu ích khi bạn muốn nội dòng và nó sẽ không được gọi ở bất kỳ nơi nào khác vì vậy nó không cần tên.
jfriend00

28

Đó là một câu hỏi cũ nhưng là một câu hỏi phổ biến. Vì vậy, hãy để tôi thêm cái này ở đây.

Với cú pháp hàm mũi tên, bạn có thể đạt được nó theo cách ngắn gọn hơn vì nó được liên kết từ vựng và có thể được xâu chuỗi.

Biểu thức hàm mũi tên là một thay thế nhỏ gọn về mặt cú pháp cho biểu thức hàm thông thường, mặc dù không có các ràng buộc riêng với các từ khóa this, đối số, super hoặc new.target.

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

Nếu bạn cần xóa trình lắng nghe sự kiện:

// 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);

Đây là một lớp lót điên rồ:

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

Phiên bản ngoan ngoãn hơn : Thích hợp hơn cho bất kỳ công việc lành mạnh nào.

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

2
Đây có vẻ là một giải pháp hợp lý nhưng khi bạn phải xóa cùng một người nghe sự kiện thì sao?
Dushyant Sabharwal

@SnnSnn: +1. Tôi đã sử dụng điều này để cung cấp một thuộc tính lớp cho trình xử lý sự kiện. Tôi vừa mới vào thisvà trình xử lý có thể truy cập những gì nó cần.
Robotron

Nếu sự hiểu biết của tôi là đúng, thì bạn thực sự đang chuyển một hàm ẩn danh làm trình xử lý sự kiện của bạn: (e) => {....} chứ không phải yourEventHandlerFunction (). Điều này sẽ gây ra sự cố nếu bạn muốn xóa trình xử lý sự kiện sau này, vì bạn đã chuyển vào một hàm ẩn danh để bắt đầu bằng ???
PowerAktar

Câu trả lời giải thích rõ ràng cách xóa trình nghe sự kiện, vì vậy không có vấn đề gì ở đó.
snnsnn

9

Một cái gì đó bạn có thể thử là sử dụng phương thức ràng buộc, tôi nghĩ rằng điều này đạt được những gì bạn yêu cầu. Nếu không có gì khác, nó vẫn rất hữu ích.

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);

2

Với bản cập nhật cho câu hỏi ban đầu, có vẻ như có sự cố với ngữ cảnh ("this") khi chuyển các trình xử lý sự kiện. Những điều cơ bản được giải thích, ví dụ tại đây http://www.w3schools.com/js/js_ Chức năng_invocation.asp

Một phiên bản làm việc đơn giản của ví dụ của bạn có thể đọc

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);

Xem thêm Javascript call () & apply () vs bind ()?


2

Câu trả lời ngắn:

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

... 

function myfunction(e, param1, param1) {
    ... 
} 

Điều này không hoạt động chính xác. Nếu giá trị của các tham số của bạn thay đổi mỗi khi bộ xử lý sự kiện được đặt, nó sẽ tạo ra kết quả không mong muốn vì nó không đóng quá giá trị của param1hoặc param2. Nếu những giá trị đó thay đổi, chúng sẽ không được đặt thành giá trị mà chúng đã có trong thời gian trình xử lý sự kiện được tạo. Chúng sẽ chỉ được đặt thành giá trị hiện tại. Ngoài ra, điều này không khác gì việc thiết lập một biến bên ngoài phạm vi của hàm trình xử lý sự kiện và tham chiếu đến biến đó trong trình xử lý sự kiện, vì vậy nó hoàn toàn không thực hiện được việc chuyển các tham số.
TetraDev

Tôi thực sự không hiểu ý của bạn nên phản hồi của tôi có thể bị tắt. Dù sao, trình xử lý sự kiện được đặt một lần (không phải lúc nào tôi cũng đoán nhưng thường đó là những gì ai đó muốn). Thứ hai, điều này nói lên khá nhiều rằng hàm xử lý là hàm của tôi và nó có 2 tham số cộng với biến "sự kiện". Thứ ba, có nó hoạt động và kết quả chính xác như mong đợi.
user3093134 Ngày

Không, nó không hoạt động. Tôi đã thử nghiệm nó chính xác như bạn đã làm và quan điểm của tôi vẫn có giá trị. Nếu param1noodlelần đầu tiên addEventListener được gọi và lần thứ hai bạn gọi nó, paramcheesebất cứ khi nào trình xử lý sự kiện clickkích hoạt, param1sẽ được đặt thành cheesevà không noodle. Do đó, nó không sử dụng "đóng" để ghi nhớ giá trị đã tồn tại tại thời điểm trình nghe sự kiện được thêm vào. Có những tình huống mà trình nghe sự kiện phải được thêm nhiều lần mà không cần phải minh họa để quan điểm của tôi có giá trị.
TetraDev

Tôi không phải là một chuyên gia và tôi chưa nghe nói về "đóng cửa" trong lập trình trước đây, vì vậy tôi không hiểu ý bạn về điều đó.
user3093134

1
Cảm ơn bạn đã kiểm tra nó, tôi chắc chắn sẽ truy cập vào các liên kết bạn đã đăng. Ngoài ra, tôi có thể nói bạn là rất lịch sự và trung thực thưa ông, giữ cho nó lên và có một ngày tốt lành :)
user3093134

0

thisbên trong doThingslà đối tượng cửa sổ. Hãy thử cái này thay thế:

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

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

    return {
        eventHandler: eventHandler
    };
};

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.