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


832

他们似乎在做同样的事情……
是现代的还是老的?还是不同的浏览器支持它们?

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

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

(我知道,很多问题,但都是相同的=)

Answers:


1011

stopPropagation 阻止事件冒泡事件链。

preventDefault 阻止浏览器对该事件进行默认操作。

例子

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和更低版本,请替换stopPropagationcancelBubble和替换preventDefaultreturnValue


所以它们有很大的不同吗?IE是否也有两种不同的事件方法?(它们可能是相同的吗?)框架在event.stop功能上都做得很奇怪……而且我从来没有遇到过麻烦。我经常冒泡。谢谢你的例子!
鲁迪

@Rudie评论了浏览器的支持。
雷诺斯

7
值得注意的是(如果您不看MSDN文档),cancelBubble并且returnValue都是属性(因此应设置cancelBubble = true;),preventDefault并且stopPropagation都是方法(应称为preventDefault();
freefaller 2014年

1
@Raynos,请注意:event.stopPropagation()不仅可以阻止事件冒泡,也可以阻止事件在捕获阶段传播(developer.mozilla.org/en-US/docs/Web/ API / Event / stopPropagation
Yuci,

1
知道按钮单击的默认操作是有帮助的,这样我就可以推断出为什么stopDefault()与按钮不同stopPropagation()。如果默认操作未调用该onclick方法,那是什么?
d512

248

术语

来自quirksmode.org

事件捕捉

使用事件捕获时

               | |
--------------- | | -----------------
| element1 | | |
| ----------- | | ----------- |
| | element2 \ / | |
| ------------------------- |
| 活动捕获|
-----------------------------------

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

事件冒泡

使用事件冒泡时

               / \
--------------- | | -----------------
| element1 | | |
| ----------- | | ----------- |
| | element2 | | | |
| ------------------------- |
| 活动起泡|
-----------------------------------

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

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

                 | | / \
----------------- | |-| | -----------------
| element1 | | | | |
| ------------- | |-| | ----------- |
| | element2 \ / | | | |
| -------------------------------- |
| 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();
}

阻止打开新标签页。


23
感谢您在捕获和冒泡之间有更深的区别,而其他答案仅解决了jQuery的问题。
floribon 2014年

@floribon说你无意冒犯raynos来回答他。
Mahi

3
@Mahi是什么?我只是在说事实,可接受的答案是使用jQuery,这不是OP所假定的,所以对我来说,这不是实际的答案。现在,这只是技术事实,没有什么私人的,也没有人可冒犯的。
floribon '16

2
您的回答非常系统,很好地演示了正在发生的事情。最初,我不想打扰您,也不想自己更改您的答案,因为我认为为清晰起见可以有所改进。这个答案向初学者解释了事件模型,因此,我认为我们可以为初学者提供的每一点帮助都将走很长一段路。我的编辑建议因通用论点而被拒绝,我不同意。如果您@Ashkan认为这些小的更改可以帮助改善答案,请合并它们。
mucaho

68

返回false;


return false; 调用它时会做3件事:

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

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

preventDefault();


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单击 。这是由于我们使用event.stopPropagation()方法阻止了向父div的传播。接下来,您将看到超链接“单击此处访问stackoverflow.com”,并替换为文本“将要执行Click事件”,然后您将立即重定向到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. 内联返回false。

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


1
很好的例子,但是如果没有jQuery,情况会更好,因为jQuery会伪造事件对象,因此在技术上有所不同。
鲁迪

1
@Rudie我更新了答案并从中删除了jquery,还添加了返回false的示例。
Keval Bhatt

17

这是这里的报价

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

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%的时间是preventDefault!错误地“停止”事件可能会导致大量麻烦。您的插件可能无法正常工作,并且第三方插件可能会变砖。更糟糕的是,您的代码破坏了网站上的其他功能。


2

Event.preventDefault-停止浏览器默认行为。现在是什么是浏览器默认行为。假设您有一个定位标记,并且具有href属性,并且该定位标记嵌套在具有click事件的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树冒泡,防止任何父处理程序收到该事件的通知。

例如,如果是的点击方法连接内的链接DIVFORM还附加有点击的方法,它会阻止DIVFORM从发射单击方法。


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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.