协慌网

登录 贡献 社区

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

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

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

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

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

答案

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 和更低版本,请将stopPropagation替换为cancelBubble ,将preventDefault替换为returnValue

术语

来自quirksmode.org

事件捕捉

使用事件捕获时

| |
---------------| |-----------------
| element1     | |                |
|   -----------| |-----------     |
|   |element2  \ /          |     |
|   -------------------------     |
|        Event CAPTURING          |
-----------------------------------

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

事件冒泡

使用事件冒泡时

/ \
---------------| |-----------------
| element1     | |                |
|   -----------| |-----------     |
|   |element2  | |          |     |
|   -------------------------     |
|        Event BUBBLING           |
-----------------------------------

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

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

| |  / \
-----------------| |--| |-----------------
| element1       | |  | |                |
|   -------------| |--| |-----------     |
|   |element2    \ /  | |          |     |
|   --------------------------------     |
|        W3C event model                 |
------------------------------------------

接口

w3.org进行事件捕获

如果捕获的EventListener希望阻止事件的进一步处理,则可以调用Event接口的stopPropagation方法。这将阻止事件的进一步分发,尽管在相同层次结构级别注册的其他EventListeners仍将接收该事件。一旦调用了事件的stopPropagation方法,对该方法的进一步调用将不会产生任何其他效果。如果不存在其他捕获stopPropagation并且尚未调用stopPropagation ,则事件将在目标本身上触发适当的EventListeners

对于事件冒泡

任何事件处理程序都可以选择通过调用Event接口的stopPropagation方法来防止进一步的事件传播。如果任何EventListener调用此方法,则将触发当前EventTarget上的所有其他EventListeners ,但气泡将在该级别停止。只需调用一次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();
}

阻止打开新标签页。

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