event.stopPropagation 和 event.preventDefault 有什么区别?

IT技术 javascript events preventdefault stoppropagation
2021-01-11 12:26:23

他们似乎在做同样的事情……
一个现代的一个古老的?或者它们是否受不同浏览器的支持?

当我自己处理事件(没有框架)时,我总是检查两者并执行两者(如果存在)。(我也有return false,但我有一种感觉,不适用于带有 的事件node.addEventListener)。

那为什么两者都有呢?我应该继续检查两者吗?或者实际上有区别吗?

(我知道,很多问题,但它们都是一样的 =))

6个回答

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>

停止传播

$("#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 的单击处理程序仍会触发。

下面是一些来自 MDN 的关于 DOM 事件属性和方法的文档:

对于 IE9 和 FF,您可以只使用 preventDefault 和 stopPropagation。

支持IE8及以下的replace stopPropagationwithcancelBubble和replace preventDefaultwithreturnValue

值得注意的是(如果你不看 MSDN 文档)cancelBubblereturnValue都是属性(所以应该设置cancelBubble = true;),preventDefault并且stopPropagation是方法(所以应该被调用preventDefault();
2021-03-16 12:26:23
所以他们很不一样?IE 是否也有两种不同的事件方法?(它们可能是一样的吗??)框架在它们的event.stop功能中都做到了这很奇怪......也很奇怪我从来没有遇到过这个问题。我经常使用冒泡。谢谢你的例子!
2021-03-18 12:26:23
@Raynos,只是一个注意事项: event.stopPropagation() 不仅阻止事件在事件链上冒泡,而且还在捕获阶段阻止事件传播(developer.mozilla.org/en-US/docs/Web/ API/事件/停止传播
2021-03-25 12:26:23
按钮的默认浏览器行为是什么?
2021-04-04 12:26:23
知道单击按钮的默认操作是什么会很有帮助,这样我就可以推理为什么stopDefault()stopPropagation(). 如果默认操作不是调用onclick方法,那是什么?
2021-04-06 12:26:23

术语

来自quirksmode.org

事件捕捉

使用事件捕获时

               | |
---------------| |-----------------
| 元素1 | | |
| -----------| |----------- |
| |元素2 \ / | |
| ------------------------- |
| 事件捕捉 |
---------------------

element1 的事件处理程序首先触发,element2 的事件处理程序最后触发。

事件冒泡

当你使用事件冒泡时

               / \
---------------| |-----------------
| 元素1 | | |
| -----------| |----------- |
| |元素2 | | | |
| ------------------------- |
| 事件冒泡 |
---------------------

element2 的事件处理程序首先触发,element1 的事件处理程序最后触发。

在 W3C 事件模型中发生的任何事件首先被捕获,直到它到达目标元素,然后再次冒泡

                 | | / \
-----------------| |--| |-----------------
| 元素1 | | | | |
| -------------| |--| |----------- |
| |元素2 \ / | | | |
| -------------------------------- |
| W3C 事件模型 |
------------------------------------------

界面

来自w3.org,用于事件捕获

如果捕获EventListener希望阻止对事件的进一步处理,它可以调用接口stopPropagation方法 Event这将阻止事件的进一步分派,尽管EventListeners在同一层次结构级别的其他注册仍将接收该事件。一旦stopPropagation 调用了事件的方法,对该方法的进一步调用就没有额外的效果。如果没有额外的捕获器存在并且 stopPropagation未被调用,则该事件会EventListeners在目标本身上触发相应的事件

对于事件冒泡

任何事件处理程序都可以选择通过调用接口stopPropagation方法来阻止进一步的事件传播Event如果有任何 EventListener调用此方法,则将触发EventListeners当前所有附加的EventTarget但冒泡将在该级别停止。只需要一次调用以stopPropagation防止进一步冒泡。

对于活动取消

取消是通过调用EventpreventDefault 方法完成的。如果在事件流的任何阶段有一个或多个EventListeners调用preventDefault,默认操作将被取消。

例子

在以下示例中,单击 Web 浏览器中的超链接会触发事件流(执行事件侦听器)和事件目标的默认操作(打开一个新选项卡)。

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

防止打开新标签页。

感谢捕获和冒泡之间更深层次的区别,而另一个答案仅解决了 jQuery 问题。
2021-03-19 12:26:23

返回假;


return false; 当你调用它时,它会做 3 件不同的事情:

  1. event.preventDefault() – 它停止浏览器的默认行为。
  2. event.stopPropagation() – 它可以防止事件传播(或“冒泡”)DOM。
  3. 停止回调执行并在调用时立即返回。

请注意,此行为与普通(非 jQuery)事件处理程序不同,在普通(非 jQuery)事件处理程序中,值得注意的是,return false它不会阻止事件冒泡。

防止默认();


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”的超链接,如果您首先单击该链接,您将获得 javascript 警报链接 单击下一步您将获得 javascript 警报div 单击,然后您将立即被重定向到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”的超链接,如果您先单击该链接,您将获得 javascript 警报链接,单击下一步,您将获得 javascript 警报div 单击下一步,您将看到超链接“单击此处访问 stackoverflow.com' 替换为文本“阻止的单击事件”,您将不会被重定向到 stackoverflow.com。这是由于 > 我们用来防止触发默认点击操作的 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 警报div Clicked 这次。这是因为我们使用 event.stopPropagation() 方法阻止了传播到父 div。接下来,您将看到超链接“单击此处访问 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() 方法阻止了传播到父 div。接下来,您将看到“单击此处访问 stackoverflow.com”的超链接被文本“阻止的单击事件”替换,并且您不会被重定向到 stackoverflow.com。这是因为我们使用 event.preventDefault() 方法阻止了这次触发默认点击操作。

示例 5:

对于 return false,我有三个示例,它们似乎都在做完全相同的事情(只是返回 false),但实际上结果却大不相同。以下是上述每一项中实际发生的情况。

案例:

  1. 从内联事件处理程序返回false 会阻止浏览器导航到链接地址,但不会阻止事件通过 DOM 传播。
  2. 从 jQuery 事件处理程序返回false 会阻止浏览器导航到链接地址,并阻止事件通过 DOM 传播。
  3. 从常规 DOM 事件处理程序返回false绝对没有任何作用。

将看到所有三个示例。

  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 事件处理程序返回false

<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 事件处理程序返回 false。

<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 文件中执行所有这些示例,看看它们是如何工作的。

很好的例子,但如果没有 jQuery 会更好,因为 jQuery 伪造事件对象,所以这在技术上是不同的。
2021-03-16 12:26:23
@Rudie 我更新了我的答案并从中删除了 jquery,还添加了返回 false 的示例。
2021-04-03 12:26:23

这是这里的报价

Event.preventDefault

preventDefault 方法阻止事件执行其默认功能。例如,您可以在 A 元素上使用 preventDefault 来阻止单击该元素离开当前页面:

//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 中冒泡。

事件停止传播

第二种方法 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 有效地阻止父元素了解其子元素上的给定事件。

虽然简单的 stop 方法可以让我们快速处理事件,但重要的是要考虑冒泡到底要发生什么。我敢打赌,开发人员真正想要的只是在 90% 的情况下防止默认!错误地“停止”事件可能会给您带来许多麻烦;您的插件可能无法正常工作,并且您的第三方插件可能会变砖。或者更糟——您的代码破坏了站点上的其他功能。

TL;DR
event.preventDefault()
阻止浏览器的默认行为(例如打开链接),但不会阻止事件冒泡 DOM。

event.stopPropagation()
防止事件冒泡 DOM,但不会停止浏览器的默认行为。

返回假;
通常在 jQuery 代码中看到,它阻止浏览器的默认行为,阻止事件冒泡 DOM,并立即从任何回调返回。

看看这个非常好的和简单的 4 分钟阅读,并附有上述作品的示例。