链接内元素的 stopPropagation/preventDefault 行为 [英] stopPropagation/preventDefault behavior on an element inside a link

查看:20

"当一个事件被分派到一个参与树的对象(例如一个元素)时,它也可以到达该对象的祖先上的事件监听器.首先,所有对象的祖先事件监听器的捕获变量设置为 true 被调用,以树顺序.其次,调用对象自己的事件侦听器.最后,只有当事件的气泡属性值为真时,才会再次调用对象的祖先事件侦听器,但现在以相反的树顺序调用."- https://dom.spec.whatwg.org/#dom-event-preventdefault

当您使用 event.stopPropagation() 时,您正在阻止任何父级(或子级,如果冒泡 = true)被通知其事件.这不会阻止它的默认事件被触发.

要检查事件是否冒泡,您可以使用 var x = event.bubbles;console.log(x);

edit:这是一个如何结合使用 event.preventDefault()event.stopPropagation() 的例子 -

var div = document.querySelector('div');var a = document.querySelector('a');a.addEventListener('click', function(event){event.preventDefault();});div.addEventListener('click', function(event) {event.stopPropagation();console.log('div');});

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script><a href="#" target="_blank"><div><input type="checkbox"/>

这将阻止附加到 的点击事件到达

之外的任何内容

是一个元素.

也是一个元素.这意味着当 stopPropagation() 用于 时, 的点击处理程序将是唯一一个继续工作.

stopPropagation(); 作用于点击处理程序事件,而不是默认浏览器事件.所以当你停止在 元素上传播时, 仍然重定向用户,因为这是默认浏览器事件.

但是,console.log('a fire.');console.log('div fires'); 不会触发,因为它们是点击处理程序,不是默认浏览器事件.

preventDefault(); 阻止执行任何默认浏览器操作,而不是单击处理程序.

由于

是一个元素,当您在 上使用 preventDefault(); 时,它将阻止附加到 的任何默认浏览器操作.<div> 来自触发.

因此,当您将 preventDefault() 添加到 <input/> 并尝试单击它时,它的状态不会改变,但是 被点击时,> 链接仍将按预期运行.

I'm trying to understand the behavior when an element inside of a <a> have a event.stopPropagation() or event.preventDefault().

In the first case, clicking in the <div> also fires the <a> event, moving it to another page. event.stopPropagation() has no effect.

If I change event.stopPropagation() to event.preventDefault(), when clicking in the div, the console logs "div", the <a> does not fires any event BUT the checkbox stops working. So event.preventDefault() affect a child element.

What I'm missing here?

.html

<a href="#" target="_blank">
  <div>
    <input type="checkbox"/>
  </div>
</a>

.js

var div = document.querySelector('div');

div.addEventListener('click', function(event) {
  event.stopPropagation();
  // event.preventDefault(); # second case
  console.log('div');
});

.css (just to make it easier to see on screen)

a {
  display: block;
  background: black;
  width: 300px;
  height: 100px;
}

div {
  background: red;
  width: 50px;
  height: 50px;
}

解决方案

event.preventDefault() will prevent both the href and checkbox from firing their default events because it is a bubbling event.

"When an event is dispatched to an object that participates in a tree (e.g. an element), it can reach event listeners on that object’s ancestors too. First all object’s ancestor event listeners whose capture variable is set to true are invoked, in tree order. Second, object’s own event listeners are invoked. And finally, and only if event’s bubbles attribute value is true, object’s ancestor event listeners are invoked again, but now in reverse tree order." - https://dom.spec.whatwg.org/#dom-event-preventdefault

When you use event.stopPropagation() you are preventing any parent (or child if bubbling = true) from being notified of it's event. This will not prevent it's default event from being fired.

To check if an event is bubbling you can use var x = event.bubbles; console.log(x);

edit: here's an example of how to use event.preventDefault() and event.stopPropagation() in conjunction -

var div = document.querySelector('div');
var a = document.querySelector('a');
a.addEventListener('click', function(event){
    event.preventDefault();
});
div.addEventListener('click', function(event) {
  event.stopPropagation();
  console.log('div');
});

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="#" target="_blank">
  <div>
    <input type="checkbox"/>
  </div>
</a>

This will prevent the click event attached to <a> from reaching anything beyond <div>

<a><div><input></div></a> is ONE element.

<div><input></div> is also ONE element. This means when stopPropagation() is used on <input> the click handler for <input> will be the only one which continues to work.

stopPropagation(); acts upon click handler events, not default browser events. So when you stop propagation on the <input> element, <a> still redirects the user, because that is it's default browser event.

However, console.log('a fired.'); and console.log('div fired'); will not trigger as they are click handlers, not default browser events.

preventDefault(); prevents any default browser actions from being executed, not click handlers.

Since <a><div><input /></div></a> is ONE element, when you use preventDefault(); on <a> it will prevent any default browser actions attached to <a> <div> or <input /> from firing.

so when you add preventDefault() to <input /> and try to click on it, it's state won't be changed, but the <a> link will still function as intended when <a> is clicked.

var input = document.querySelector('div');
var a = document.querySelector('a');
var div = document.querySelector('a');

a.addEventListener('click', function(event){
    //event.preventDefault();
    //event.stopPropagation();
    console.log('a fired.');
});

div.addEventListener('click', function(event) {
  //event.preventDefault();
  //event.stopPropagation(); 
  console.log('div fired.');
});

input.addEventListener('click', function(event) {
  event.preventDefault();
  //event.stopPropagation(); 
  console.log('input fired');
});

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!-- <a><div><input></div></a> is ONE element. -->
<a href="#" target="_blank" style="border:solid 1px #ccc;background:green;">this is a link
    <!-- <div><input></div> is also ONE element. This means when stopPropagation() is used on this element, all click handler events within this element will not trigger, but <a></a> will -->
  <div style="border: solid 1px #2779aa;">
    <input type="checkbox"/>
  </div>
</a>

这篇关于链接内元素的 stopPropagation/preventDefault 行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆