防止在点击div时触发焦点事件

76
这个问题与我之前的问题相似,单击已聚焦DIV时的单击操作, 但这次主要话题是:如何防止在单击div之一时触发焦点事件。 上次我有一个tabindex为'-1'的div以便在单击时成为可聚焦元素,现在我有一些tabindex>0的div列表,以便它们可以在使用Tab键聚焦时获得焦点。
<div tabindex='1'>Div one</div>
<div tabindex='1'>Div two</div>
<div tabindex='1'>Div tree</div>
<div tabindex='1'>Div four</div>

一些样式:

div {
    height: 20px;
    width: 60%;
    border: solid 1px blue;
    text-align: center;
}
div:focus {
    border: solid 2px red;
    outline: none;
}

现在我使用一个标志(action)来在第二次点击div时触发一个操作(alert),如果已经聚焦,则只需单击一次,例如使用TAB。

var action = false;
$('div')
    .click(function(e){
        e.stopImmediatePropagation();
        if(action){alert('action');}
        action = true;})
    .focus(function(){action = true;})
    .blur(function(){action = false;});

上面代码的问题是,聚焦事件(focus event)被触发了,这意味着stopImmediatePropagation不像我预期的那样工作。当注释掉聚焦事件线时,两个点击动作可以正常工作,但是当div通过TAB键获得焦点时,仍然需要双击。

以下是示例:http://jsfiddle.net/3MTQK/1/

5个回答

127

这里有示例。

我认为你遗漏了一些部分:

  1. event.stopPropagation() 用于阻止事件冒泡。你可以在这里 阅读相关内容

  2. event.stopImmediatePropagation() 除了防止执行元素上其他处理程序之外,该方法还通过隐式调用 event.stopPropagation() 来停止冒泡。你可以在这里 阅读相关内容

  3. 如果你想要阻止浏览器默认事件,则应使用 event.preventDefault()。你可以在这里 阅读相关内容

  4. click = mousedown + mouseup -> 当鼠标按下成功时,焦点将集中在 HTML 元素上。因此,你应该使用 'mousedown' 而不是绑定 'click' 事件。请参见我的示例。

  5. 你不能使用一个动作布尔值来确定点击了哪个 div 以及它被点击了多少次。查看我的示例,了解如何处理它。


如果我将两个事件绑定到一个元素上,会怎么样?例如,如果我写:$(document).on("touchstart click", ".myelement", function (e) {e.stopImmediatePropagation(); //在这里运行函数}) ....如果我在平板设备上,触摸开始会首先触发并停止所有其他事件吗?因为现在如果我点击一个元素并保持手指按下状态,触摸和点击事件都会触发,我的函数会运行两次。stopImmediatePropagation 能解决这个问题吗? - Alex
“mousedown” 成功是什么意思? - clapas

52
为了在点击 div 元素时防止焦点丢失,只需使用 mousedown + event.preventDefault()。使用 mousedown 替代 click,因为如@Selvakumar Arumugam所解释的那样,当 mousedown 成功时会触发焦点事件,而 event.preventDefault() 将停止浏览器事件(包括我们的焦点)。
以下是代码示例:
$('#div').on('mousedown', function(event) {
// do your magic
event.preventDefault();
});

2
mousedown有很多缺点,它不是一个简单的开关。在随处使用click之前,请小心谨慎。 - Jamie Marshall
1
@JamieMarshall 缺点比如...? - Asker
1
@Asker - mousedown不会像你预期的那样触发触摸事件。许多原生组件,如下拉框,根据mousedown和mouseup具有默认行为。有很多情况下,mousedown并不等同于click。在过去,它们可能更加相似,但在今天的世界中,这并不是一个简单的切换。 - Jamie Marshall

16

简单来说,

// ❌ Don't (focus already set on mouse down)
onClick={e => e.preventDefault()}

// ✔️ Do (prevent focus)
onMouseDown={e => e.preventDefault()} 

2
不幸的是,这也禁用了其他默认行为,比如选择文本 :( - Matthias Samsel

1

目前的解决方案是将您的选择器从简单的“div”限制为切换类名的系统,这样您就可以控制焦点事件在哪个元素上触发。虽然更加繁琐并需要更多的异常编码,但可以完成工作。


我猜这个也可以,但是被采纳的答案要好太多了(在mousedown处理程序中使用event.preventDefault())。 - Jon z

-1
var action = false;
$('div')
    .click(function(e){
        e.stopImmediatePropagation();
        if(action){alert('action');}
        action = true;})
    .focus(function(){action = true;})
    .blur(function(){action = false;});

2
你的回答可以通过添加更多关于代码的信息以及它如何帮助提问者来改进。 - Tyler2P

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