event.preventDefault () so với return false (không có jQuery)


84

Tôi tự hỏi nếu event.preventDefault()return falsegiống nhau.

Tôi đã thực hiện một số bài kiểm tra và có vẻ như

  • Ví dụ: nếu trình xử lý sự kiện được thêm bằng cách sử dụng mô hình cũ

    elem.onclick = function(){
        return false;
    };
    

    Sau đó, return falsengăn hành động mặc định, như event.preventDefault().

  • addEventListenerVí dụ: nếu trình xử lý sự kiện được thêm bằng cách sử dụng

    elem.addEventListener(
        'click',
        function(e){
            return false;
        },
        false
    );
    

    Sau đó, return falsekhông ngăn cản hành động mặc định.

Có phải tất cả các trình duyệt đều hoạt động như vậy không?

Có nhiều sự khác biệt hơn giữa event.preventDefault()return false?

Tôi có thể tìm thấy một số tài liệu ở đâu (tôi không có trong MDN) về cách return falsecư xử như thế nào event.preventDefault()trong một số trường hợp?


Câu hỏi của tôi chỉ là về javascript thuần, không phải jQuery, vì vậy vui lòng không đánh dấu nó là bản sao của event.preventDefault () so với return false , ngay cả khi cả hai câu hỏi có tiêu đề gần như giống nhau.


Bản sao của stackoverflow.com/questions/1357118/… Nếu bạn đọc câu hỏi, bạn sẽ nhận thấy rằng đó là một vấn đề JS chung chung không phải là vấn đề dành riêng cho jQuery. jQuery chỉ được sử dụng để làm cho mã ví dụ ngắn gọn / sạch sẽ nhất có thể.
RaYell

13
@RaYell Không, vì jQuery return falsehoạt động khác với JavaScript đơn thuần. Hơn nữa, câu hỏi khác không có bất kỳ câu trả lời nào giải thích sự khác biệt trong JS đơn giản (chỉ có một nhận xét giải thích nó, nhưng rất khó tìm). Vì vậy, tôi nghĩ rằng tốt hơn là có hai câu hỏi khác nhau.
Oriol

Câu trả lời:


55

Các tài liệu W3C Object Model Sự kiện Thông số kỹ thuật trong 1.3.1. Giao diện đăng ký sự kiện nói rằng handleEventtrong EventListener không có giá trị trả về:

handleEvent Phương thức này được gọi bất cứ khi nào một sự kiện xảy ra thuộc loại mà giao diện EventListener đã được đăng ký. [...] Không có giá trị trả lại

dưới 1.2.4. Sự kiện Huỷ bỏ tài liệu cũng nói rằng

Việc hủy bỏ được thực hiện bằng cách gọi phương thức PreventDefault của Sự kiện. Nếu một hoặc nhiều EventListists gọi PreventDefault trong bất kỳ giai đoạn nào của luồng sự kiện, hành động mặc định sẽ bị hủy.

điều này sẽ không khuyến khích bạn sử dụng bất kỳ hiệu ứng nào mà việc trả về true / false có thể có trong bất kỳ trình duyệt và cách sử dụng nào event.preventDefault().

Cập nhật

HTML5 thực sự chỉ định cách xử lý giá trị trả về khác nhau. Phần 7.1.5.1 của Thông số kỹ thuật HTML nói rằng

Nếu giá trị trả về là giá trị sai boolean WebIDL thì hãy hủy sự kiện.

cho mọi thứ trừ sự kiện "di chuột qua".

Phần kết luận

Tôi vẫn khuyên bạn nên sử dụng event.preventDefault()trong hầu hết các dự án vì bạn sẽ tương thích với thông số kỹ thuật cũ và các trình duyệt cũ hơn. Chỉ khi bạn chỉ cần hỗ trợ các trình duyệt tiên tiến, trả về false để hủy bỏ là được.


2
Liên kết này được viết vào năm 2000. Thông số HTML5: w3.org/TR/html5/webappapis.html#event-handler-attributes có vẻ như nó xử lý giá trị trả về cho nhiều sự kiện (không phải di chuột qua): "Nếu giá trị trả về là boolean WebIDL giá trị sai, sau đó hủy sự kiện "
Charles L.

Và từ một số thử nghiệm nhanh trong chrome, cả hai đều trả về false và event.preventDefault () không ngừng lan truyền. Tín dụng chủ yếu để @Oriol: Xem ngừng tuyên truyền so với bình thường
Charles L.

Fiddle này so sánh hành vi của stopPropagation(), preventDefault()return false: jsfiddle.net/m1L6of9x . Trên các trình duyệt hiện đại, hai trình duyệt sau có cùng hoạt động.
Erik Koopmans

5

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ụ: onclickthuộc tính trên một phần tử nút): trả về false để hủy sự kiện
  • addEventListenerlà 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 clicksự 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=functionNamelà 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) {
    // want to prevent link navigation
    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); // to avoid truncation of output

... 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 functionNamenó đượ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ì onclickhà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 onclicktrả về giá trị trả về (false) từ myHandlerFunc.

Bạn cũng có thể loại bỏ các return false;từ myHandlerFuncvà 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 onclickbằng javascript , khi bạn đang đặt onclicktrực tiếp trong html chứ không phải với javascript (như các ví dụ của tôi), onclickgiá 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 onclickbằng javascript, bạn cần chú ý đến loại. Nếu bạn nói element.setAttribute('onclick', myHandlerFunc()) myHandlerFuncsẽ 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) {
    // want to prevent link navigation
    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); // to avoid truncation of output

...trình diễn:

function onclick(event) {
return (function eventHandler (e) {
        // want to prevent link navigation
        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 eventtham 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 onclickphạ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 eventlà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) {
    // want to prevent link navigation
    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); // to avoid truncation of output

kết quả:

function eventHandler (ev) {
    // want to prevent link navigation
    alert('eventHandler ran');
    console.log(ev);
    return false;
}

Vì vậy, bạn đã có thể thấy sự khác biệt. Với addEventListenerchúng tôi không được bao bọc trong một onclickchức năng. Trình xử lý của chúng tôi nhận eventtham 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) {
    // want to prevent link navigation
    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); // to avoid truncation of output

cho ...

function eventHandler (ev) {
    // want to prevent link navigation
    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 addEventListenerviệ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 onclickaddEventListenertrong 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:

...

  1. 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 falsehủy bỏ sự kiện cho cả hai addEventListeneronclick.

Tuy nhiên, nếu bạn nhìn vào định nghĩa được liên kết của họ về event-handlerbạ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 falsehủ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 addEventListenercó API khác.

addEventListenerAPI 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ọ.


-2

Sự khác biệt giữa PreventDefault, stopPropogation, return false

Bảng hiển thị sự khác biệt

Hành động mặc định - Hành động phía máy chủ khi tăng sự kiện kiểm soát.

Giả sử chúng ta có điều khiển div và bên trong nó, chúng ta có một nút. Vì vậy, div là điều khiển cha của nút. Chúng tôi có nhấp chuột phía máy khách và nhấp chuột phía máy chủ sự kiện của nút. Ngoài ra, chúng tôi có sự kiện nhấp chuột phía khách hàng của div.

Khi nhấp vào sự kiện của nút ở phía máy khách, chúng tôi có thể kiểm soát các hành động của kiểm soát gốc và mã phía máy chủ bằng cách sử dụng ba cách sau:

  • return false- Điều này chỉ cho phép sự kiện phía máy khách của điều khiển. Sự kiện phía máy chủ và sự kiện phía máy khách của điều khiển mẹ không được kích hoạt.

  • preventDefault()- Điều này cho phép kiểm soát sự kiện phía máy khách và kiểm soát cha của nó. Sự kiện phía máy chủ tức là. Hành động mặc định của điều khiển không được kích hoạt.

  • stopPropogation()- Điều này cho phép phía máy khách cũng như phía máy chủ sự kiện điều khiển. Sự kiện phía máy khách của kiểm soát không được phép.


21
Bạn đã sai, return falsekhông ngừng truyền bá, do đó, IS kiểm soát phụ huynh sa thải ( demo ). Hơn nữa, tôi không chắc ý bạn với " sự kiện nhấp chuột phía máy chủ ".
Oriol

6
@ Người mới bắt đầu, vui lòng bỏ qua câu trả lời này.
pilau

4
Điều này vô nghĩa về các sự kiện phía máy chủ là gì? -1
Mark Amery

Tôi nghĩ nội dung phía máy chủ đang nghĩ về ASP, nơi bạn có thể xử lý các sự kiện trên máy chủ.
Andrew

5
Không có "phía máy chủ" khi nói về JavaScript và các sự kiện.
rawpower

-12

return falsechỉ dành cho IE, event.preventDefault()được hỗ trợ bởi các trình duyệt hiện đại chrome, ff ...


9
Nhưng trên Firefox return falsehoạt động giống như event.preventDefault()khi xử lý sự kiện được thêm vào sử dụng mô hình cũ
Oriol
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.