Sự khác biệt giữa event.stopPropagation và event.preventDefault là gì?


834

Họ dường như đang làm điều tương tự ...
Là một người hiện đại và một người già? Hay chúng được hỗ trợ bởi các trình duyệt khác nhau?

Khi tôi tự xử lý các sự kiện (không có khung), tôi chỉ luôn kiểm tra cả hai và thực hiện cả hai nếu có. (Tôi cũng vậy return false, nhưng tôi có cảm giác không hoạt động với các sự kiện kèm theo node.addEventListener).

Vậy tại sao cả hai? Tôi có nên tiếp tục kiểm tra cho cả hai? Hay thực sự có một sự khác biệt?

(Tôi biết, rất nhiều câu hỏi, nhưng tất cả chúng đều giống nhau =))

Câu trả lời:


1015

stopPropagation ngăn chặn sự kiện từ bong bóng lên chuỗi sự kiện.

preventDefault ngăn hành động mặc định mà trình duyệt thực hiện đối với sự kiện đó.

Ví dụ

ngăn chặn Mặc định

$("#but").click(function (event) {
  event.preventDefault()
})
$("#foo").click(function () {
  alert("parent click event fired!")
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="foo">
  <button id="but">button</button>
</div>

stopPropagation

$("#but").click(function (event) {
  event.stopPropagation()
})
$("#foo").click(function () {
  alert("parent click event fired!")
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="foo">
  <button id="but">button</button>
</div>

Với stopPropagation, chỉ có buttontrình xử lý nhấp chuột được gọi trong khi divtrình xử lý nhấp chuột không bao giờ kích hoạt.

Nếu bạn sử dụng preventDefault, chỉ có hành động mặc định của trình duyệt bị dừng nhưng trình xử lý nhấp chuột của div vẫn kích hoạt.

Dưới đây là một số tài liệu về các thuộc tính và phương thức sự kiện DOM từ MDN:

Đối với IE9 và FF, bạn chỉ có thể sử dụng ngăn chặn Default & stopPropagation.

Để hỗ trợ IE8 và thấp hơn thay thế stopPropagationbằng cancelBubblevà thay thế preventDefaultbằngreturnValue


Vì vậy, họ rất khác nhau? IE có hai phương thức sự kiện khác nhau không? (Có thể chúng giống nhau ??) Thật kỳ lạ khi các khung làm cả hai trong event.stopchức năng của chúng ... Thật kỳ lạ tôi chưa bao giờ gặp rắc rối với điều đó. Tôi sử dụng bong bóng rất nhiều. Cảm ơn ví dụ!
Rudie

@Rudie nhận xét về hỗ trợ trình duyệt.
Raynos

7
Nó đáng chú ý (trong trường hợp bạn không nhìn vào các tài liệu MSDN) mà cancelBubblereturnValueđều thuộc tính (vì vậy nên thiết lập cancelBubble = true;), và điều đó preventDefaultstopPropagationđược các phương pháp (vì vậy nên được gọi preventDefault();)
freefaller

1
@Raynos, chỉ cần một lưu ý: event.stopPropagation () không chỉ ngăn sự kiện nổi lên chuỗi sự kiện, mà còn ngăn chặn sự lan truyền sự kiện trong giai đoạn bắt giữ ( developer.mozilla.org/en-US/docs/Web/ API / Sự kiện / stopPropagation )
Yuci

1
Sẽ rất hữu ích khi biết hành động mặc định là gì đối với một lần bấm nút để tôi có thể giải thích tại sao stopDefault()không hoạt động giống như vậy stopPropagation(). Nếu hành động mặc định không gọi onclickphương thức thì đó là gì?
d512

249

Thuật ngữ

Từ quirksmode.org :

Chụp sự kiện

Khi bạn sử dụng chụp sự kiện

               | |
--------------- | | -----------------
| phần tử1 | | |
| ----------- | | ----------- |
| | phần tử2 \ / | |
| ------------------------- |
| Sự kiện CAPTURING |
-----------------------------------

trình xử lý sự kiện của Element1 kích hoạt trước, trình xử lý sự kiện của Element2 kích hoạt trước.

Sự kiện sủi bọt

Khi bạn sử dụng bong bóng sự kiện

               / \
--------------- | | -----------------
| phần tử1 | | |
| ----------- | | ----------- |
| | phần tử2 | | | |
| ------------------------- |
| Sự kiện BUBBLING |
-----------------------------------

trình xử lý sự kiện của Element2 kích hoạt trước, trình xử lý sự kiện của Element1 kích hoạt trước.

Bất kỳ sự kiện nào diễn ra trong mô hình sự kiện W3C trước tiên được ghi lại cho đến khi nó đạt đến phần tử đích và sau đó lại nổi bong bóng .

                 | | / \
----------------- | | - | | -----------------
| phần tử1 | | | | |
| ------------- | | - | | ----------- |
| | phần tử2 \ / | | | |
| -------------------------------- |
| Mô hình sự kiện W3C |
------------------------------------------

Giao diện

Từ w3.org , để chụp sự kiện :

Nếu việc chụp EventListenermong muốn ngăn không cho xử lý thêm sự kiện xảy ra, nó có thể gọi stopPropagationphương thức của Eventgiao diện. Điều này sẽ ngăn việc gửi thêm sự kiện, mặc dù EventListenersđăng ký bổ sung ở cùng cấp thứ bậc sẽ vẫn nhận được sự kiện. Khi stopPropagation phương thức của một sự kiện đã được gọi, các cuộc gọi tiếp theo đến phương thức đó không có hiệu lực bổ sung. Nếu không có người bắt giữ bổ sung tồn tại và stopPropagationchưa được gọi, sự kiện sẽ kích hoạt sự phù hợp EventListenerstrên chính mục tiêu.

Đối với bong bóng sự kiện :

Bất kỳ trình xử lý sự kiện nào cũng có thể chọn để ngăn chặn sự lan truyền sự kiện hơn nữa bằng cách gọi stopPropagationphương thức của Eventgiao diện. Nếu bất kỳ EventListenergọi phương thức này, tất cả bổ sung EventListenerstrên hiện tại EventTargetsẽ được kích hoạt nhưng bong bóng sẽ chấm dứt ở mức đó. Chỉ một cuộc gọi đến stopPropagationlà cần thiết để ngăn chặn sự sủi bọt hơn nữa.

Đối với hủy bỏ sự kiện :

Hủy được thực hiện bằng cách gọi Eventcủa preventDefault phương pháp. Nếu một hoặc nhiều EventListenerscuộc gọi preventDefaulttrong 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.

Ví dụ

Trong các ví dụ sau, nhấp chuột vào siêu liên kết trong trình duyệt web sẽ kích hoạt luồng của sự kiện (trình lắng nghe sự kiện được thực thi) và hành động mặc định của mục tiêu sự kiện (một tab mới được mở).

HTML:

<div id="a">
  <a id="b" href="http://www.google.com/" target="_blank">Google</a>
</div>
<p id="c"></p>

JavaScript:

var el = document.getElementById("c");

function capturingOnClick1(ev) {
    el.innerHTML += "DIV event capture<br>";
}

function capturingOnClick2(ev) {
    el.innerHTML += "A event capture<br>";
}

function bubblingOnClick1(ev) {
    el.innerHTML += "DIV event bubbling<br>";
}

function bubblingOnClick2(ev) {
    el.innerHTML += "A event bubbling<br>";
}

// The 3rd parameter useCapture makes the event listener capturing (false by default)
document.getElementById("a").addEventListener("click", capturingOnClick1, true);
document.getElementById("b").addEventListener("click", capturingOnClick2, true);
document.getElementById("a").addEventListener("click", bubblingOnClick1, false);
document.getElementById("b").addEventListener("click", bubblingOnClick2, false);

Ví dụ 1 : kết quả là đầu ra

DIV event capture
A event capture
A event bubbling
DIV event bubbling

Ví dụ 2 : thêm stopPropagation()vào hàm

function capturingOnClick1(ev) {
    el.innerHTML += "DIV event capture<br>";
    ev.stopPropagation();
}

kết quả trong đầu ra

DIV event capture

Người nghe sự kiện đã ngăn chặn sự truyền bá đi xuống và đi lên của sự kiện. Tuy nhiên, nó không ngăn được hành động mặc định (mở tab mới).

Ví dụ 3 : thêm stopPropagation()vào hàm

function capturingOnClick2(ev) {
    el.innerHTML += "A event capture<br>";
    ev.stopPropagation();
}

hoặc chức năng

function bubblingOnClick2(ev) {
    el.innerHTML += "A event bubbling<br>";
    ev.stopPropagation();
}

kết quả trong đầu ra

DIV event capture
A event capture
A event bubbling

Điều này là do cả hai người nghe sự kiện được đăng ký trên cùng một mục tiêu sự kiện. Những người nghe sự kiện đã ngăn chặn sự truyền bá đi lên của sự kiện. Tuy nhiên, họ không ngăn hành động mặc định (mở tab mới).

Ví dụ 4 : thêm preventDefault()vào bất kỳ chức năng nào, ví dụ

function capturingOnClick1(ev) {
    el.innerHTML += "DIV event capture<br>";
    ev.preventDefault();
}

ngăn một tab mới mở.


23
Cảm ơn sự phân biệt sâu sắc hơn giữa chụp và sủi bọt trong khi câu trả lời khác chỉ giải quyết các mối quan tâm của jQuery.
floribon

@floribon nói rằng bạn không có ý định xúc phạm raynos vì câu trả lời của anh ấy.
Mahi

3
@Mahi cái gì? Tôi chỉ nói sự thật, câu trả lời được chấp nhận là sử dụng jQuery không phải do OP giả định, vì vậy với tôi đó không phải là câu trả lời thực sự. Bây giờ đó chỉ là thực tế kỹ thuật, không có gì cá nhân và không ai bị xúc phạm.
floribon

2
Câu trả lời của bạn rất có hệ thống và thể hiện độc đáo những gì đang diễn ra. Ban đầu tôi không muốn làm phiền bạn và tự mình thực hiện một số thay đổi cho câu trả lời của bạn, vì tôi nghĩ nó có thể được cải thiện một chút cho rõ ràng. Câu trả lời này giải thích mô hình sự kiện cho người mới bắt đầu và như vậy, tôi nghĩ rằng mỗi chút trợ giúp chúng ta có thể cung cấp cho người mới bắt đầu đều đi một chặng đường dài. Đề xuất chỉnh sửa của tôi đã bị từ chối bởi các đối số chung chung, mà tôi không đồng ý. Nếu bạn, @Ashkan, cảm thấy rằng những thay đổi nhỏ này có thể giúp cải thiện câu trả lời, vui lòng kết hợp chúng.
mucaho

68

trả lại sai;


return false; thực hiện 3 điều riêng biệt khi bạn gọi nó:

  1. event.preventDefault() - Nó dừng hành vi mặc định của trình duyệt.
  2. event.stopPropagation() - Điều này ngăn sự kiện lan truyền (hoặc sôi sùng sục lên) DOM.
  3. Dừng thực hiện gọi lại và trả về ngay lập tức khi được gọi.

Lưu ý rằng hành vi này khác với các trình xử lý sự kiện thông thường (không phải jQuery), trong đó, đáng chú ý, return falsekhông ngăn sự kiện nổi lên.

ngăn chặn Mặc định();


preventDefault(); hiện một điều: Nó dừng hành vi mặc định của trình duyệt.

Khi nào sử dụng chúng?


Chúng tôi biết những gì họ làm nhưng khi nào sử dụng chúng? Đơn giản là nó phụ thuộc vào những gì bạn muốn thực hiện. Sử dụng preventDefault();nếu bạn muốn, chỉ có thể ngăn chặn hành vi trình duyệt mặc định. Sử dụng trả lại sai; khi bạn muốn ngăn hành vi trình duyệt mặc định và ngăn sự kiện lan truyền DOM. Trong hầu hết các tình huống mà bạn sẽ sử dụng return false; những gì bạn thực sự muốn là preventDefault().

Ví dụ:


Hãy thử hiểu với các ví dụ:

Chúng ta sẽ thấy ví dụ JAVASCRIPT thuần túy

Ví dụ 1:

<div onclick='executeParent()'>
  <a href='https://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
  function executeChild() {
    alert('Link Clicked');
  }

  function executeParent() {
    alert('div Clicked');
  }
</script>

Chạy mã ở trên, bạn sẽ thấy siêu liên kết 'Nhấp vào đây để truy cập stackoverflow.com' ngay bây giờ nếu bạn nhấp vào liên kết đó trước, bạn sẽ nhận được cảnh báo javascript Liên kết được nhấp vào Tiếp theo, bạn sẽ nhận được thông báo javascript được nhấp và ngay lập tức bạn sẽ được chuyển hướng đến stackoverflow.com.

Ví dụ 2:

<div onclick='executeParent()'>
  <a href='https://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
  function executeChild() {
    event.preventDefault();
    event.currentTarget.innerHTML = 'Click event prevented'
    alert('Link Clicked');
  }

  function executeParent() {
    alert('div Clicked');
  }
</script>

Chạy mã ở trên, bạn sẽ thấy siêu liên kết 'Nhấp vào đây để truy cập stackoverflow.com' ngay bây giờ nếu bạn nhấp vào liên kết đó trước tiên bạn sẽ nhận được cảnh báo javascript Liên kết được nhấp vào Tiếp theo, bạn sẽ nhận được thông báo javascript được nhấp vào Tiếp theo bạn sẽ thấy siêu liên kết ' Nhấp vào đây để truy cập stackoverflow.com 'được thay thế bằng văn bản' Đã ngăn chặn sự kiện nhấp chuột 'và bạn sẽ không được chuyển hướng đến stackoverflow.com. Điều này là do phương thức event.preventDefault () mà chúng tôi đã sử dụng để ngăn hành động nhấp chuột mặc định được kích hoạt.

Ví dụ 3:

<div onclick='executeParent()'>
  <a href='https://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
  function executeChild() {
    event.stopPropagation();
    event.currentTarget.innerHTML = 'Click event prevented'
    alert('Link Clicked');
  }

  function executeParent() {
    alert('div Clicked');
  }
</script>

Lần này nếu bạn nhấp vào Liên kết thì hàm execParent () sẽ không được gọi và bạn sẽ không nhận được cảnh báo javascript được nhấp vào lần này. Điều này là do chúng tôi đã ngăn chặn sự lan truyền đến div cha bằng cách sử dụng phương thức event.stopPropagation (). Tiếp theo, bạn sẽ thấy siêu liên kết 'Nhấp vào đây để truy cập stackoverflow.com' được thay thế bằng văn bản 'Sự kiện nhấp sẽ được thực hiện' và ngay lập tức bạn sẽ được chuyển hướng đến stackoverflow.com. Điều này là do chúng tôi chưa ngăn hành động nhấp mặc định kích hoạt lần này bằng phương thức event.preventDefault ().

Ví dụ 4:

<div onclick='executeParent()'>
  <a href='https://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
  function executeChild() {
    event.preventDefault();
    event.stopPropagation();
    event.currentTarget.innerHTML = 'Click event prevented'
    alert('Link Clicked');
  }

  function executeParent() {
    alert('Div Clicked');
  }
</script>

Nếu bạn nhấp vào Liên kết, hàm execParent () sẽ không được gọi và bạn sẽ không nhận được cảnh báo javascript. Điều này là do chúng tôi đã ngăn chặn sự lan truyền đến div cha bằng cách sử dụng phương thức event.stopPropagation (). Tiếp theo, bạn sẽ thấy siêu liên kết 'Nhấp vào đây để truy cập stackoverflow.com' được thay thế bằng văn bản 'Nhấp vào sự kiện bị chặn' và bạn sẽ không được chuyển hướng đến stackoverflow.com. Điều này là do chúng tôi đã ngăn hành động nhấp chuột mặc định kích hoạt lần này bằng cách sử dụng phương thức event.preventDefault ().

Ví dụ 5:

Để trả về false, tôi có ba ví dụ và tất cả dường như đang làm chính xác cùng một thứ (chỉ trả về false), nhưng trong thực tế, kết quả hoàn toàn khác nhau. Đây là những gì thực sự xảy ra trong mỗi điều trên.

các trường hợp:

  1. Trả về false từ trình xử lý sự kiện nội tuyến sẽ ngăn trình duyệt điều hướng đến địa chỉ liên kết, nhưng nó không ngăn sự kiện lan truyền qua DOM.
  2. Trả về false từ trình xử lý sự kiện jQuery ngăn trình duyệt điều hướng đến địa chỉ liên kết và nó ngăn sự kiện truyền qua DOM.
  3. Trả về false từ trình xử lý sự kiện DOM thông thường hoàn toàn không có gì.

Sẽ thấy cả ba ví dụ.

  1. Nội tuyến trả về sai.

<div onclick='executeParent()'>
  <a href='https://stackoverflow.com' onclick='return false'>Click here to visit stackoverflow.com</a>
</div>
<script>
  var link = document.querySelector('a');

  link.addEventListener('click', function() {
    event.currentTarget.innerHTML = 'Click event prevented using inline html'
    alert('Link Clicked');
  });


  function executeParent() {
    alert('Div Clicked');
  }
</script>

  1. Trả về false từ trình xử lý sự kiện jQuery.

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
  <a href='https://stackoverflow.com'>Click here to visit stackoverflow.com</a>
</div>
<script>
  $('a').click(function(event) {
    alert('Link Clicked');
    $('a').text('Click event prevented using return FALSE');
    $('a').contents().unwrap();
    return false;
  });
  $('div').click(function(event) {
    alert('Div clicked');
  });
</script>

  1. Trả về false từ một trình xử lý sự kiện DOM thông thường.

<div onclick='executeParent()'>
  <a href='https://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
  function executeChild() {
    event.currentTarget.innerHTML = 'Click event prevented'
    alert('Link Clicked');
    return false
  }

  function executeParent() {
    alert('Div Clicked');
  }
</script>

Hy vọng những ví dụ này là rõ ràng. Hãy thử thực hiện tất cả các ví dụ này trong một tệp html để xem cách chúng hoạt động.


1
Các ví dụ tốt, nhưng thậm chí còn tốt hơn nếu không có jQuery, vì jQuery giả mạo đối tượng sự kiện, vì vậy về mặt kỹ thuật thì khác.
Rudie

1
@Rudie Tôi đã cập nhật câu trả lời của mình và xóa jquery khỏi nó, đồng thời thêm ví dụ trả về false.
Keval Bhatt

17

Đây là trích dẫn từ đây

Sự kiện.preventDefault

Phương thức notifyDefault ngăn sự kiện thực hiện chức năng mặc định của nó. Ví dụ: bạn sẽ sử dụng ngăn chặn Default trên phần tử A để dừng nhấp vào phần tử đó khỏi trang hiện tại:

//clicking the link will *not* allow the user to leave the page 
myChildElement.onclick = function(e) { 
    e.preventDefault(); 
    console.log('brick me!'); 
};

//clicking the parent node will run the following console statement because event propagation occurs
logo.parentNode.onclick = function(e) { 
    console.log('you bricked my child!'); 
};

Trong khi chức năng mặc định của phần tử bị gạch, sự kiện tiếp tục tạo ra DOM.

Sự kiện.stopPropagation

Phương thức thứ hai, stopPropagation, cho phép chức năng mặc định của sự kiện xảy ra nhưng ngăn sự kiện lan truyền:

//clicking the element will allow the default action to occur but propagation will be stopped...
myChildElement.onclick = function(e) { 
    e.stopPropagation();
    console.log('prop stop! no bubbles!'); 
};

//since propagation was stopped by the child element's onClick, this message will never be seen!
myChildElement.parentNode.onclick = function(e) { 
    console.log('you will never see this message!'); 
};

stopPropagation ngăn chặn hiệu quả các yếu tố cha mẹ biết về một sự kiện nhất định trên con của nó.

Mặc dù phương pháp dừng đơn giản cho phép chúng tôi xử lý nhanh các sự kiện, nhưng điều quan trọng là phải suy nghĩ về chính xác những gì bạn muốn xảy ra với bong bóng. Tôi cá rằng tất cả các nhà phát triển thực sự muốn là ngăn chặn 90% thời gian! Việc "dừng" không chính xác một sự kiện có thể khiến bạn gặp nhiều rắc rối; plugin của bạn có thể không hoạt động và plugin của bên thứ ba của bạn có thể bị brick. Hoặc tệ hơn nữa - mã của bạn phá vỡ chức năng khác trên một trang web.


2

Event.preventDefault- dừng hành vi mặc định của trình duyệt. Bây giờ đến hành vi mặc định của trình duyệt là gì. Giả sử bạn có thẻ neo và nó có thuộc tính href và thẻ neo này được lồng bên trong thẻ div có sự kiện nhấp chuột. Hành vi mặc định của thẻ neo là khi nhấp vào thẻ neo, nó sẽ điều hướng, nhưng event.preventDefault làm gì thì nó dừng điều hướng trong trường hợp này. Nhưng nó không bao giờ ngăn chặn sự sủi bọt của sự kiện hoặc sự leo thang của sự kiện tức là

<div class="container">
 <a href="#" class="element">Click Me!</a>
</div>

$('.container').on('click', function(e) {
 console.log('container was clicked');
});

$('.element').on('click', function(e) {
  e.preventDefault(); // Now link won't go anywhere
  console.log('element was clicked');
});

Kết quả sẽ là

"phần tử đã được nhấp"

"container đã được bấm"

Bây giờ event.StopPropation nó dừng bong bóng của sự kiện hoặc leo thang sự kiện. Bây giờ với ví dụ trên

$('.container').on('click', function(e) {
  console.log('container was clicked');
});

$('.element').on('click', function(e) {
  e.preventDefault(); // Now link won't go anywhere
  e.stopPropagation(); // Now the event won't bubble up
 console.log('element was clicked');
});

Kết quả sẽ là

"phần tử đã được nhấp"

Để biết thêm thông tin, hãy tham khảo liên kết này https://codeplanet.io/preventdefault-vs-stoppropagation-vs-stopim Ngaypropagation /


1

event.preventDefault(); Dừng hành động mặc định của một yếu tố xảy ra.

event.stopPropagation(); Ngăn chặn sự kiện làm nổi lên cây DOM, ngăn không cho bất kỳ trình xử lý cha mẹ nào được thông báo về sự kiện này.

Ví dụ: nếu có một liên kết với phương thức nhấp được đính kèm bên trong DIVhoặc FORMcũng có phương thức nhấp được đính kèm, nó sẽ ngăn phương thức DIVhoặc FORMnhấp vào bắn.


-3

$("#but").click(function(event){
console.log("hello");
  event.preventDefault();
 });


$("#foo").click(function(){
 alert("parent click event fired !");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="foo">
  <button id="but">button</button>
</div>

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.