点击元素并将鼠标拖动到其外部

4

我相信有人已经遇到过这样的问题,但不幸的是我找不到答案。

window.onload = function (e) {
    var foo = document.getElementById('foo');
    foo.addEventListener('click', function(e) {
      e.stopPropagation();
      e.preventDefault();
      alert('foo');
    });
    document.body.addEventListener('click', function(e) {
      alert('body');
    });
};
#foo {
  width: 200px;
  height: 200px;
  background-color: red;
  cursor: pointer;
}
body,
html {
  width: 100%;
  height: 100%;
}
<div id="foo">Click me</div>

请查看jsfiddle并按照以下步骤描述我的问题:

1)单击红色div 2)不要释放鼠标按钮并将其拖到外面

如您所见,body click函数会触发。这正是我想要禁用的。我想检测用户是否在div内单击,如果然后拖到了外部,则不应发生任何事情!


event.stopImmediatePropagation() 可以解决这个问题。 - somethinghere
我认为你正在使用错误的事件!尝试使用mousedown和mouseup。而要使用拖动,这些事件很有用:drag、dragend、dragleave、dragenter、dragover、dragstart... 来自MDN - Anonymous0day
这也很有趣 - 即使 mouseup 在另一个不冒泡事件的元素上,它仍然会在 body 上触发 click : http://jsfiddle.net/y0q8rw0g/. - Shikkediel
2个回答

1

看起来Firefox是唯一一个当光标移开原始元素时不会触发点击的浏览器。在与webkit相关的浏览器上,没有原始mousedown的痕迹,但所有事件数据都基于事实,就像在body上完全触发了点击一样。因此,无法根据点击本身进行区分。可能有一些解决方法,但这里有一个 - 检查任何点击是否源自元素上的mousedown

window.addEventListener('load', function() {

var foo = document.getElementById('foo'), fromfoo,
origin  = document.getElementById('origin');

foo.addEventListener('mousedown', function(e) {

    e.stopPropagation();

    fromfoo = true;
});

document.body.addEventListener('mousedown', function() {

    fromfoo = false;
});

foo.addEventListener('mouseup', function(e) {

    e.stopPropagation();

    if (fromfoo) origin.innerHTML = 'foo';
});

document.body.addEventListener('mouseup', function() {

    if (fromfoo) origin.innerHTML = 'different';
    else origin.innerHTML = 'body';
});
});
html, body {
  width:100%;
  height:100%;
  margin: 0;
}

#origin {
  float: right;
  margin: 50px 100px;
}

#foo {
  width:200px;
  height:200px;
  background-color: red;
  cursor:pointer;
}
<div id="origin"></div>
<div id="foo">Click me</div>

这是一个相当巧妙的解决方法,但其中一部分原因是为了与 Mozilla 实现反向兼容。

编辑 - 非常奇怪,这就是 Microsoft 文档 所说的:

例如,如果用户在单击对象时将鼠标移开,然后再释放鼠标指针,则不会发生 onclick 事件。

但实际上并非如此。


更新 - 在长时间的搜索后,我也找到了这份报告:

https://code.google.com/p/chromium/issues/detail?id=484655

似乎至少存在一些错误行为或对W3规范的误解。显然,这是IE已知的问题,并且最近在Chrome中出现了这个问题。关于IE的这个问题,来自2013年的一个问题看起来也与此有关。仍然可能会有用的是,有人发布了一个小插件:

在jQuery mousedown处理程序中添加叠加层后,Internet Explorer泄漏点击事件


非常抱歉之前没有回复您,实际上您的答案非常有帮助,我也有类似的想法,但是这个解决方案并不完美。我会继续寻找更理想的解决方案,如果没有更好的选择,我会选择您的答案作为解决方案! - gogachinchaladze
谢谢回复 - 对于我的不耐烦表示抱歉。我已经进行了广泛的调查,记录了事件本身并在每个细节上进行了比较。body 上的幽灵点击似乎与直接点击它是相同的。不幸的是,点击本身无法被阻止,只能阻止它们的默认操作以及它们是否会冒泡。因此,我认为没有办法避免使用这些不同的事件。看起来与所有浏览器匹配有点过于复杂,但似乎是不可避免的。你发布的这个问题非常有趣,在 Google 上找不到任何结果。 - Shikkediel
是的,我也认为没有人能找到更好的解决方案,但让我们再等一天,然后我会检查你的答案!再次感谢你的帮助,伙计! - gogachinchaladze
如果有人提供更好的解决方案,我会很高兴看到,并且一定会点赞。干杯! - Shikkediel

0

使用:

e.stopImmediatePropagation();

阻止调用同一事件的其他监听器。
来源 MDN:https://developer.mozilla.org/zh-CN/docs/Web/API/Event/stopImmediatePropagation

window.onload = function (e) {
    var foo = document.getElementById('foo');
    foo.addEventListener('click', function(e) {
      e.stopImmediatePropagation();
      e.preventDefault();
      alert('foo');
    });
    document.body.addEventListener('click', function(e) {
      alert('body');
    });
};
#foo {
  width: 200px;
  height: 200px;
  background-color: red;
  cursor: pointer;
}
body,
html {
  width: 100%;
  height: 100%;
}
<div id="foo">Click me</div>


我不认为那会解决问题 :( 你测试过了吗? - gogachinchaladze
刚刚更新了 jsfiddle http://jsfiddle.net/gogachinchaladze/n5a1t4cc/,但是还像之前一样工作。 - gogachinchaladze

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接