Làm cách nào để chuyển sự kiện dưới dạng đối số đến một trình xử lý sự kiện nội tuyến trong 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>

Có một số câu hỏi tương tự đã được đặt ra.

Nhưng trong mã của tôi, tôi đang cố gắng lấy các phần tử con đã được nhấp, thích ahoặcspan .

Vậy đâu là cách chính xác để chuyển eventdưới dạng một đối số đến trình xử lý sự kiện hoặc làm thế nào để nhận sự kiện bên trong trình xử lý mà không truyền đối số?

biên tập

Tôi biết addEventListenerjQueryvui lòng cung cấp giải pháp để chuyển sự kiện cho người xử lý inlinesự kiện.



5
Có lý do chính đáng nào để sử dụng trình xử lý sự kiện nội tuyến thay vì chuyển sang addEventListener không? en.wikipedia.org/wiki/Unobtrusing_JavaScript
Xotic750

2
@ Xotic750 Đối với tôi là có, không cần quan tâm đến việc liên kết lại chúng theo cách thủ công mỗi khi tải động hoặc tải lại html thông qua ajax chẳng hạn.
Wadih M.

Câu trả lời:


166

để chuyển eventđối tượng:

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

để có được đứa trẻ được nhấp element(nên được sử dụng với eventtham số:

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

để vượt qua elementchính nó (DOMElement):

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

xem ví dụ trực tiếp trên jsFiddle


11
(Và đối với bất kỳ ai thắc mắc: Có, điều này hoạt động trên Chrome, Firefox, v.v., mặc dù một số [ví dụ: Firefox] không có eventđối tượng toàn cục . Đó là do ngữ cảnh mà trình xử lý DOM0 được gọi có một eventđối tượng , ngay cả khi [trên một số trình duyệt] nó không phải là toàn cầu.)
TJ Crowder

thisđề cập đến p, nhưng tôi đang cố lấy ahoặcspan
user1643156

3
Vượt qua ´event´ là cách duy nhất mà tôi biết, miễn là nó được hỗ trợ. Phân tích cú pháp ´ cái này không có ích trong tình huống này
Xotic750

5
@ user1643156 Điều đó rất quan trọng. tham số phải được đặt tên chính xác là "sự kiện"
The-null-Pointer-

1
Câu trả lời của Wadih M. là cách tốt hơn thế này. Điều này gây hiểu lầm (giống như những người khác tương tự), khiến mọi người tin rằng tham số "(sự kiện)" nên được đưa vào lệnh gọi hàm, khi thực sự, JavaScript đã có sẵn thông số "sự kiện" bên trong hàm được gọi, vì vậy không cần phải khai báo nó (tôi đã mất nhiều ngày để nhận ra rằng việc thay đổi tên biến không có gì khác biệt, bởi vì nó không thực sự được chuyển). Ngoài ra, lời giải thích được đưa ra ở đó đã loại bỏ mọi nghi ngờ về lý do tại sao JS hoạt động như vậy (có lẽ không nên, nhưng điều đó không phải do tôi đánh giá ...)
Cyberknight

15

Vì các sự kiện nội tuyến được thực thi dưới dạng hàm nên bạn có thể chỉ cần sử dụng các đối số .

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

'Sự kiện' được đề cập trong câu trả lời được chấp nhận thực sự là tên của đối số được truyền cho hàm. Nó không liên quan gì đến sự kiện toàn cầu.


Mẹo tốt. Khi mọi người sẽ bắt đầu áp dụng các thành phần web call()apply()sẽ chứng minh được điều cần thiết trong việc mô phỏng các khả năng liên kết dữ liệu có sẵn trong các khung js chính thống. Một mẹo bổ sung là làm một cái gì đó tương tự như Object.assign(this.querySelector('my-btn'), this)bên trong một thành phần web và thì đấy là ràng buộc dữ liệu. Bạn có thể truy cập bất kỳ phương thức nào của lớp thành phần web mẹ từ các sự kiện nội tuyến onclick="toggleBtnActive.call(this, true)".
Adrian Moisa

8

Bạn không cần phải vượt qua this, đã có eventđối tượng được truyền theo mặc định tự động, trong event.targetđó có đối tượng có đối tượng mà nó đến. Bạn có thể làm sáng cú pháp của mình:

Điều này:

<p onclick="doSomething()">

Sẽ làm việc với điều này:

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

Bạn không cần khởi tạo eventđối tượng, nó đã ở đó. Hãy thử nó ra. Và event.targetsẽ chứa toàn bộ đối tượng gọi nó, mà bạn đã gọi nó là "this" trước đây.

Bây giờ nếu bạn kích hoạt động doSomething () từ một nơi nào đó trong mã của bạn, bạn sẽ nhận thấy rằng đó eventlà không xác định. Điều này là do nó không được kích hoạt từ sự kiện nhấp chuột. Vì vậy, nếu bạn vẫn muốn kích hoạt sự kiện một cách giả tạo, chỉ cần sử dụng dispatchEvent:

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

Sau đó doSomething()sẽ thấy eventevent.targetnhư thường lệ!

Không cần phải đi thiskhắp nơi và bạn có thể giữ cho chữ ký hàm của mình không bị dây thông tin và đơn giản hóa mọi thứ.


Ít nhất trên IE11, điều này không đúng, Không có đối số mặc định.
cskwg

1
@cskwg Nó cũng hoạt động cho IE11. Nó hoạt động trên tất cả các trình duyệt chính vì điều này cần thiết để tương thích ngược. Như tôi đã đề cập trong câu trả lời, chỉ khi hàm javascript được kích hoạt từ một sự kiện, đó là trường hợp duy nhất mà một sự kiện tồn tại, sẽ có một đối tượng đã được gọi là "sự kiện" mà bạn có thể dễ dàng truy cập bên trong hàm của mình mà không cần phải chuyển thêm dây cho nguyên mẫu chức năng của bạn. Tôi vừa thực hiện một bài kiểm tra trên máy của mình với IE11 cho một sự kiện onclick và biến 'sự kiện' chứa một "đối tượng PointerEvent".
Wadih M.
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.