Яка різниця між event.stopPropagation та event.preventDefault?


833

Вони, здається, роблять те саме ...
Є один сучасний і один старий? Або вони підтримуються різними браузерами?

Коли я обробляю події самостійно (без фреймворку), я завжди перевіряю їх на обидва та виконую обидва, якщо вони є. (Я також return false, але у мене є відчуття, що не працює з подіями, пов'язаними з node.addEventListener).

То чому обидва? Чи варто продовжувати перевірку обох? Або насправді є різниця?

(Я знаю, багато питань, але всі вони однакові =))

Відповіді:


1012

stopPropagation зупиняє подію від барботування в ланцюзі подій.

preventDefault запобігає дії за замовчуванням, яку браузер робить у цій події.

Приклади

предотвратиЗамовчання

$("#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>

З stopPropagation, викликається лише buttonобробник клацань , а divобробник клацань ніколи не запускається.

Якщо ви ніби використовуєте preventDefault, зупиняється лише дія за замовчуванням у веб-переглядачі, але обробник кліків Div все ще спрацьовує.

Нижче наведено деякі документи про властивості подій і методи DOM з MDN:

Для IE9 та FF ви можете просто використовувати prevenDefault & stopPropagation.

Для підтримки IE8 і нижньої заміни stopPropagationна cancelBubbleі замінити preventDefaultнаreturnValue


Так вони дуже різні? Чи є в IE два різні методи подій для цього також? (Можливо, вони однакові ??) Дивно, що фреймворки виконують обоє у своїй event.stopфункції ... Також дивно, я ніколи з цим не мав проблем. Я багато використовую барботаж. Дякую за приклад!
Rudie

@Rudie прокоментував підтримку браузера.
Райнос

7
Варто зазначити (в разі , якщо ви не дивіться на документи MSDN) , що cancelBubbleі returnValueобидва властивості (так повинно бути безліч cancelBubble = true;), і що preventDefaultі stopPropagationє методи (так слід називати preventDefault();)
freefaller

1
@Raynos, лише одна примітка: event.stopPropagation () не тільки зупиняє подію з бульбашкою по ланцюгу подій, але й зупиняє розповсюдження події на фазі захоплення ( developer.mozilla.org/en-US/docs/Web/ API / Подія / stopPropagation )
Ючі

1
Було б корисно знати, що таке дія за замовчуванням для натискання кнопки, щоб я міг пояснити, чому stopDefault()не працює так само, як stopPropagation(). Якщо дія за замовчуванням не викликає onclickметод, що це?
d512

249

Термінологія

З сайту quirksmode.org :

Захоплення події

Коли ви використовуєте захоплення подій

               | |
--------------- | | -----------------
| елемент1 | | |
| ----------- | | ----------- |
| | елемент2 \ / | |
| ------------------------- |
| CAPTURING події |
-----------------------------------

спочатку спрацьовує обробник події element1, останній обробник події елемента2.

Подія кипіла

Під час використання подій

               / \
--------------- | | -----------------
| елемент1 | | |
| ----------- | | ----------- |
| | елемент2 | | | |
| ------------------------- |
| Подія BUBBLING |
-----------------------------------

спочатку запускається обробник події елемента2, обробляється подія елементу1.

Будь-яка подія, яка відбувається в моделі подій W3C, спочатку фіксується, поки не досягне цільового елемента, а потім знову роздується .

                 | | / \
----------------- | | - | | -----------------
| елемент1 | | | | |
| ------------- | | - | | ----------- |
| | елемент2 \ / | | | |
| -------------------------------- |
| Модель подій W3C |
------------------------------------------

Інтерфейс

Від w3.org , для захоплення подій :

Якщо захоплення EventListenerбажає запобігти подальшій обробці події, воно може викликати stopPropagationметод Eventінтерфейсу. Це запобіжить подальше надсилання події, хоча додаткові EventListenersзареєстровані на тому ж рівні ієрархії все ще отримають подію. Після stopPropagation виклику методу події подальші виклики цього методу не дають додаткового ефекту. Якщо немає додаткових захоплювачів і stopPropagationне було викликано, подія запускає відповідну EventListenersдля самої цілі.

Для барботування подій :

Будь-який обробник подій може вирішити, щоб запобігти подальшому поширенню подій, викликаючи stopPropagationметод Eventінтерфейсу. Якщо хтось EventListenerвикликає цей метод, все додаткове EventListenersв поточному EventTargetперіоді буде спрацьовано, але барботаж припиниться на цьому рівні. stopPropagationПотрібен лише один дзвінок, щоб не допустити подальшого бурчання.

Для скасування події :

Скасування здійснюється за допомогою виклику методу Event's preventDefault. Якщо один або більше EventListenersдзвінків preventDefaultпід час будь-якої фази потоку події, дію за замовчуванням буде скасовано.

Приклади

У наступних прикладах натискання гіперпосилання у веб-браузері запускає потік події (виконуються слухачі подій) та дію за замовчуванням події за замовчуванням (відкривається нова вкладка).

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

Приклад 1 : це призводить до виводу

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

Приклад 2 : додавання stopPropagation()до функції

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

Результати на виході

DIV event capture

Слухач події перешкоджав подальшому зменшенню події вниз та вгору. Однак це не завадило дії за замовчуванням (відкриття нової вкладки).

Приклад 3 : додавання stopPropagation()до функції

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

або функція

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

Результати на виході

DIV event capture
A event capture
A event bubbling

Це відбувається тому, що обидва слухачі подій зареєстровані в одній цілі події. Слухачі події завадили подальше поширення події вгору. Однак вони не завадили дії за замовчуванням (відкриття нової вкладки).

Приклад 4 : додавання, наприклад, preventDefault()до будь-якої функції

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

запобігає відкриттю нової вкладки.


23
Дякуємо за більш глибоку відмінність між захопленням та бульбашкою, а інша відповідь стосується лише проблем jQuery.
floribon

@floribon кажуть, що ви не маєте наміру ображати Райноса за його відповідь.
Махі

3
@Mahi що? Я просто кажу факти, що прийнята відповідь використовує jQuery, який не передбачається ОП, тому для мене це не фактична відповідь. Тепер це лише технічний факт, нічого особистого і нікого не ображати.
флорібон

2
Ваша відповідь дуже систематична і гарно демонструє, що відбувається. Спочатку я не хотів вас турбувати і вносити деякі зміни у вашу відповідь, тому що я думаю, це можна було б трохи покращити для наочності. Ця відповідь пояснює модель події для початківців, і тому я думаю, що кожна допомога, яку ми можемо надати початківцям, проходить довгий шлях. Моя пропозиція щодо редагування була відхилена загальними аргументами, з якими я не згоден. Якщо ви, @Ashkan, вважаєте, що ці невеликі зміни можуть допомогти покращити відповідь, будь ласка, включіть їх.
mucaho

68

повернути помилкове;


return false; робить 3 окремі речі, коли ви його називаєте:

  1. event.preventDefault() - Це зупиняє поведінку браузера за замовчуванням.
  2. event.stopPropagation() - Це заважає події розповсюджувати (або "кипувати") DOM.
  3. Зупиняє виконання зворотного дзвінка і повертається негайно при виклику.

Зауважте, що така поведінка відрізняється від звичайних (не-jQuery) обробників подій, в яких, зокрема, return falseне зупиняється подія від бурбання.

prevenDefault ();


preventDefault(); робить одне: зупиняє поведінку браузера за замовчуванням.

Коли їх використовувати?


Ми знаємо, що вони роблять, але коли їх використовувати? Просто це залежить від того, що ви хочете досягти. Використовуйте, preventDefault();якщо ви хочете "просто" запобігти поведінці браузера за замовчуванням. Використовуйте return false; коли ви хочете запобігти поведінці веб-переглядача за замовчуванням і запобігти поширенню події DOM. У більшості ситуацій, коли ви використовуєте return false; що ти насправді хочеш preventDefault().

Приклади:


Спробуємо розібратися на прикладах:

Ми побачимо чистий приклад JAVASCRIPT

Приклад 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>

Запустіть наведений вище код , ви побачите гіперпосилання «Натисніть тут , щоб відвідати stackoverflow.com» Тепер , якщо натиснути на це посилання , спочатку ви отримаєте повідомлення яваскрипт Link Кликов Далі ви отримаєте повідомлення Javascript DIV Clicked і ви відразу будете перенаправлені stackoverflow.com.

Приклад 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>

Запустіть наведений вище код , ви побачите гіперпосилання «Натисніть тут , щоб відвідати stackoverflow.com» Тепер , якщо натиснути на це посилання , спочатку ви отримаєте повідомлення яваскрипт Link Кликов Далі ви отримаєте повідомлення Javascript Див Clicked Далі ви побачите гіперпосилання " Натисніть тут, щоб відвідати stackoverflow.com "замінено текстом" Клацання події запобігло ", і ви не будете переспрямовані на stackoverflow.com. Це пов'язано з методом> to event.preventDefault (), який ми використовували для запобігання ініціюванню дії за замовчуванням за замовчуванням.

Приклад 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>

На цей раз , якщо ви натиснете на посилання функцію executeParent () не викликатися , і ви не отримаєте попередження JavaScript Alert DIV Clicked на цей раз. Це пов'язано з тим, що ми перешкодили розповсюдженню на батьківський поділ методом event.stopPropagation (). Далі ви побачите гіперпосилання "Клацніть тут, щоб відвідати stackoverflow.com" замінено текстом "Подія натискання буде виконана", і ви негайно будете перенаправлені на stackoverflow.com. Це пов’язано з тим, що ми не перешкодили дії цього натискання за замовчуванням запустити цього разу методом event.preventDefault ().

Приклад 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>

Якщо ви натиснете на Посилання, функція ExecuteParent () не буде викликана, і ви не отримаєте попередження javascript. Це пов'язано з тим, що ми перешкодили розповсюдженню на батьківський поділ методом event.stopPropagation (). Далі ви побачите гіперпосилання "Клацніть тут, щоб відвідати stackoverflow.com" замінено на текст "Перешкоджати події натискання", і ви не будете перенаправлені на stackoverflow.com. Це тому, що ми не давали цього разу запустити дію натискання за замовчуванням за допомогою методу event.preventDefault ().

Приклад 5:

Для повернення помилкових у мене є три приклади, і всі, здається, роблять абсолютно те саме (просто повертають помилкове), але насправді результати зовсім інші. Ось що насправді відбувається у кожному з вищезазначених.

випадки:

  1. Повернення помилково з обробника подій вбудованого перешкоджає браузеру переходити до адреси посилання, однак це не перешкоджає поширенню події через DOM.
  2. Повернення помилки з обробника подій jQuery заважає браузеру переходити до адреси посилання, і це перешкоджає поширенню події через DOM.
  3. Повернення помилки з звичайного обробника подій DOM абсолютно нічого не робить.

Побачимо всі три приклади.

  1. Вбудований зворотній помилковий.

<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. Повернення помилки з обробника подій 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. Повернення помилки зі звичайного обробника події DOM.

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

Сподіваюсь, ці приклади зрозумілі. Спробуйте виконати всі ці приклади у файлі html, щоб побачити, як вони працюють.


1
Хороші приклади, але було б навіть краще без jQuery, тому що jQuery підробляє об'єкт події, тому технічно це інакше.
Руді

1
@Rudie Я оновив свою відповідь і видалив jquery з неї, а також додав приклад для повернення false.
Кеваль Бхатт

17

Це цитата звідси

Event.preventDefault

Метод prevenDefault заважає події виконувати свої функції за замовчуванням. Наприклад, ви використовуєте prevenDefault на елементі A, щоб зупинити натискання цього елемента на вихід з поточної сторінки:

//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!'); 
};

У той час як функціонал за замовчуванням елемента цегляний, подія продовжує переповнювати DOM.

Event.stopPropagation

Другий метод - stopPropagation - дозволяє функціонувати за замовчуванням події, але запобігає поширенню події:

//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 ефективно зупиняє батьківські елементи від того, щоб дізнатися про дану подію для своєї дитини.

Хоча простий метод зупинки дозволяє нам швидко впоратись з подіями, важливо подумати про те, що саме ви хочете статися з бульбашкою. Б'юсь об заклад, що все, що розробник дуже хоче, це запобігати за замовчуванням 90% часу! Неправильне "зупинення" події може спричинити вам численні неприємності внизу; ваші плагіни можуть не працювати, а ваші сторонні плагіни можуть бути закладені в цегли. Або ще гірше - ваш код порушує інші функції на сайті.


2

Event.preventDefault - зупиняє поведінку браузера за замовчуванням. Тепер з'являється те, що поведінка браузера за замовчуванням. Припустимо, у вас є тег прив’язки, і він має атрибут href, і цей тег прив’язки вкладається всередині тегу div, який отримав подію кліку. Поведінка тега якоря за замовчуванням - це при натисканні на тег прив’язки, він повинен переходити, але те, що робить event.preventDefault, це зупиняє навігацію в цьому випадку. Але це ніколи не зупиняє бурхливість події або ескалацію події, тобто

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

Результат буде

"елемент було натиснуто"

"контейнер було натиснуто"

Тепер event.StopPropation він зупиняє барботаж події або ескалацію події. Тепер з вищенаведеним прикладом

$('.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');
});

Результат буде

"елемент було натиснуто"

Для отримання додаткової інформації перейдіть за цим посиланням https://codeplanet.io/preventdefault-vs-stoppropagation-vs-stopimmediatepropagation/


1

event.preventDefault(); Зупиняє дію елемента за замовчуванням від того, що відбувається.

event.stopPropagation(); Запобігає події від барботування дерева DOM, запобігаючи повідомленню будь-яких батьківських обробників про подію.

Наприклад, якщо є посилання з методом клацання, приєднаним всередині DIVабо, FORMякий також додає метод клацання, це запобігає запусканню методу DIVабо FORMнатискання.


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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.