Dưới đây là một số ví dụ có thể giúp mọi người hiểu và khắc phục sự cố của họ tốt hơn.
TL; DR
on*
trình xử lý sự kiện (ví dụ: onclick
thuộc tính trên một phần tử nút): trả về false để hủy sự kiện
addEventListener
là một API khác, các giá trị trả về (ví dụ false
) bị bỏ qua: sử dụng event.preventDefault()
.
onclick="<somejs>"
có sự nhầm lẫn tiềm ẩn của riêng nó bởi vì <somejs>
được bao bọc trong nội dung của một hàm onclick.
- Sử dụng devtools của trình duyệt
getEventListeners
API để xem trình xử lý sự kiện của bạn trông như thế nào để khắc phục sự cố nếu trình xử lý sự kiện của bạn không hoạt động như mong đợi.
Thí dụ
Ví dụ này dành riêng cho click
sự kiện có<a>
liên kết ... nhưng có thể khái quát cho hầu hết các loại sự kiện.
Chúng tôi có một liên kết (liên kết) với lớp js-some-link-hook
mà chúng tôi muốn mở một phương thức và ngăn bất kỳ điều hướng trang nào xảy ra.
Các ví dụ dưới đây được chạy trong google chrome (71) trên MacOS Mojave.
Một cạm bẫy lớn là giả định rằng đó onclick=functionName
là hành vi giống như việc sử dụngaddEventListener
Giả sử chúng ta có một thẻ liên kết (liên kết) mà chúng ta muốn xử lý bằng javascript khi javascript được bật. Chúng tôi không muốn trình duyệt đi theo liên kết khi được nhấp vào ("ngăn chặn hành vi mặc định").
<a href="https://www.example.com/url/to/go/to/when/no/javascript"
class="js-some-link-hook">click me!</a>
thuộc tính onclick
function eventHandler (event) {
alert('eventHandler ran');
return false;
}
function addEventListenerToElement () {
var link = document.querySelector('.js-some-link-hook');
link.setAttribute('onclick', eventHandler);
}
addEventListenerToElement();
Sau đó chạy trong bảng điều khiển devtools của trình duyệt:
var el = document.querySelector('a.js-some-link-hook'),
listener = getEventListeners(el).click[0].listener;
console.log(''+listener);
... và bạn thấy:
function onclick(event) {
function eventHandler (event) {alert('eventHandler ran'); return false;}
}
Điều này không hoạt động ở tất cả. Khi sử dụng onclick=
chức năng xử lý của bạn được bao bọc trong một chức năng khác.
Bạn có thể thấy rằng định nghĩa hàm của tôi được bao gồm nhưng không được gọi vì tôi đã chỉ định tham chiếu hàm mà không gọi nó. tức là chúng ta onclick="functionName()"
không cần onclick="functionName"
chắc chắn rằng functionName
nó được chạy khi phần tử được nhấp vào.
Hơn nữa, bạn có thể thấy rằng ngay cả khi hàm của tôi được gọi và hàm của tôi trả về false ... thì onclick
hàm sẽ không trả về giá trị sai đó ... được yêu cầu để 'hủy' sự kiện.
Để khắc phục điều này, chúng ta có thể đặt thành onclick
để return myHandlerFunc();
đảm bảo rằng onclick
trả về giá trị trả về (false) từ myHandlerFunc
.
Bạn cũng có thể loại bỏ các return false;
từ myHandlerFunc
và thay đổi onclick
được myHandlerFunc(); return false;
nhưng điều này làm cho ít cảm giác như bạn có thể muốn giữ logic với nhau trong chức năng xử lý của bạn.
Lưu ý khi thiết lập onclick
bằng javascript , khi bạn đang đặt onclick
trực tiếp trong html chứ không phải với javascript (như các ví dụ của tôi), onclick
giá trị thuộc tính là kiểu chuỗi và mọi thứ đều hoạt động. Nếu bạn đang thiết lập onclick
bằng javascript, bạn cần chú ý đến loại. Nếu bạn nói element.setAttribute('onclick', myHandlerFunc())
myHandlerFunc
sẽ chạy ngay bây giờ và kết quả sẽ được lưu trữ trong thuộc tính ... chứ không phải chạy trên mỗi lần nhấp chuột. Thay vào đó, bạn nên đảm bảo giá trị thuộc tính được đặt dưới dạng chuỗi. element.setAttribute('onclick', 'return myHandlerFunc();')
Bây giờ chúng ta thấy nó hoạt động như thế nào, chúng ta có thể sửa đổi mã để làm bất cứ điều gì chúng ta muốn. Ví dụ kỳ lạ cho mục đích minh họa (không sử dụng mã này):
function eventHandler (e) {
alert('eventHandler ran');
console.log(e);
return false;
}
function addEventListenerToElement () {
var link = document.querySelector('.js-some-link-hook');
link.setAttribute('onclick', 'return ('+eventHandler+')(event);');
}
addEventListenerToElement();
Bạn thấy rằng chúng tôi đã gói định nghĩa hàm eventHandler của chúng tôi thành chuỗi. Cụ thể: một hàm tự thực thi với câu lệnh trả về ở phía trước.
Một lần nữa trong bảng điều khiển chrome devtools:
var el = document.querySelector('a.js-some-link-hook'),
listener = getEventListeners(el).click[0].listener;
console.log(''+listener);
...trình diễn:
function onclick(event) {
return (function eventHandler (e) {
alert('eventHandler ran');
console.log(e);
return false;
})(event);
}
... vâng, điều đó sẽ hoạt động. Chắc chắn là đủ nếu chúng tôi nhấp vào liên kết, chúng tôi nhận được cảnh báo và loại bỏ cảnh báo, trang không điều hướng đến bất kỳ đâu hoặc làm mới.
Một lưu ý nữa về onclick
... Nếu bạn muốn nhận và sử dụng event
tham số tại thời điểm diễn ra sự kiện, bạn cần lưu ý rằng nó có tên là "sự kiện". Bạn có thể truy cập điều này trong trình xử lý của mình bằng cách sử dụng tên event
(có sẵn thông qua onclick
phạm vi chức năng mẹ ). Hoặc bạn có thể xây dựng trình xử lý của mình để lấy event
làm tham số (tốt hơn để thử nghiệm) ... ví dụ onclick="return myEventHandler(event);"
hoặc như bạn thấy trong ví dụ trước.
addEventListener
function eventHandler (ev) {
alert('eventHandler ran');
console.log(ev);
return false;
}
function addEventListenerToElement () {
var link = document.querySelector('.js-some-link-hook');
link.addEventListener('click', eventHandler, false);
}
addEventListenerToElement();
trình duyệt devtools:
var el = document.querySelector('a.js-some-link-hook'),
listener = getEventListeners(el).click[0].listener;
console.log(''+listener);
kết quả:
function eventHandler (ev) {
alert('eventHandler ran');
console.log(ev);
return false;
}
Vì vậy, bạn đã có thể thấy sự khác biệt. Với addEventListener
chúng tôi không được bao bọc trong một onclick
chức năng. Trình xử lý của chúng tôi nhận event
tham số trực tiếp (và vì vậy chúng tôi có thể gọi nó bất cứ thứ gì chúng tôi muốn). Ngoài ra, của chúng tôi return false
ở "cấp cao nhất" ở đây và chúng tôi không phải lo lắng về việc thêm một câu lệnh trả lại bổ sung như với onclick
.
Vì vậy, có vẻ như nó sẽ hoạt động. Nhấp vào liên kết, chúng tôi nhận được thông báo. Loại bỏ cảnh báo và trang điều hướng / làm mới. tức là sự kiện KHÔNG bị hủy bằng cách trả về false.
Nếu chúng ta tra cứu thông số kỹ thuật (xem tài nguyên ở dưới cùng), chúng ta thấy rằng hàm gọi lại / xử lý của chúng ta cho addEventListener không hỗ trợ kiểu trả về. Chúng tôi có thể trả lại bất cứ thứ gì chúng tôi muốn, nhưng vì nó không phải là một phần của giao diện / API của trình duyệt nên nó không có bất kỳ tác dụng nào.
Giải pháp: sử dụng event.preventDefault()
thay vì return false;
...
function eventHandler (ev) {
ev.preventDefault();
alert('eventHandler ran');
}
function addEventListenerToElement () {
var link = document.querySelector('.js-some-link-hook');
link.addEventListener('click', eventHandler, false);
}
addEventListenerToElement();
trình duyệt devtools ...
var el = document.querySelector('a.js-some-link-hook'),
listener = getEventListeners(el).click[0].listener;
console.log(''+listener);
cho ...
function eventHandler (ev) {
ev.preventDefault();
alert('eventHandler ran');
}
...như mong đợi.
Kiểm tra lại:
- Nhấp vào liên kết.
- Nhận thông báo.
- Loại bỏ cảnh báo.
- Không có điều hướng hoặc làm mới trang xảy ra ... đó là những gì chúng tôi muốn.
Vì vậy, với addEventListener
việc sử dụng event.preventDefault()
như trả về false không làm gì cả.
Tài nguyên
Thông số html5 ( https://www.w3.org/TR/html5/webappapis.html#events ) gây nhầm lẫn vì chúng sử dụng cả hai onclick
và addEventListener
trong các ví dụ của chúng và chúng nói như sau:
Thuật toán xử lý trình xử lý sự kiện cho trình xử lý sự kiện H và đối tượng sự kiện E như sau:
...
- Xử lý giá trị trả về như sau:
...
Nếu giá trị trả về là giá trị sai boolean Web IDL, thì hãy hủy sự kiện.
Vì vậy, nó dường như ngụ ý rằng return false
hủy bỏ sự kiện cho cả hai addEventListener
và onclick
.
Tuy nhiên, nếu bạn nhìn vào định nghĩa được liên kết của họ về event-handler
bạn sẽ thấy:
Một trình xử lý sự kiện có tên, luôn bắt đầu bằng "on" và theo sau là tên của sự kiện mà nó dự định.
...
Trình xử lý sự kiện được hiển thị theo một trong hai cách.
Cách đầu tiên, chung cho tất cả các trình xử lý sự kiện, là thuộc tính IDL của trình xử lý sự kiện.
Cách thứ hai là như một thuộc tính nội dung của trình xử lý sự kiện. Trình xử lý sự kiện trên các phần tử HTML và một số trình xử lý sự kiện trên các đối tượng Window được hiển thị theo cách này.
https://www.w3.org/TR/html5/webappapis.html#event-handler
Vì vậy, có vẻ như việc return false
hủy bỏ sự kiện thực sự chỉ áp dụng cho các trình xử lý sự kiện onclick
(hoặc nói chung on*
) và không áp dụng cho các trình xử lý sự kiện được đăng ký thông qua addEventListener
có API khác.
Vì addEventListener
API không được đề cập trong thông số kỹ thuật html5 (chỉ các on*
trình xử lý sự kiện) ... nên sẽ ít khó hiểu hơn nếu chúng mắc kẹt với các on*
trình xử lý sự kiện kiểu trong các ví dụ của họ.