onclick() 和 onblur() 排序问题

Posted

技术标签:

【中文标题】onclick() 和 onblur() 排序问题【英文标题】:onclick() and onblur() ordering issue 【发布时间】:2013-07-20 02:12:13 【问题描述】:

我有一个输入字段,它会显示一个自定义下拉菜单。我想要以下功能:

当用户点击输入字段外的任意位置时,菜单应被移除。 更具体地说,如果用户单击菜单内的 div,则应删除该菜单,并且应根据单击的 div 进行特殊处理。

这是我的实现:

输入字段有一个onblur() 事件,当用户在输入字段外单击时删除菜单(通过将其父级的innerhtml 设置为空字符串)。菜单中的 div 也有onclick() 事件执行特殊处理。

问题是onclick() 事件在单击菜单时永远不会触发,因为输入字段的onblur() 首先触发并删除菜单,包括onclick()s!

我通过将菜单 div 的 onclick() 拆分为 onmousedown()onmouseup() 事件并在鼠标按下时设置一个全局标志来解决问题,该标志在鼠标抬起时被清除,类似于 this answer 中的建议。因为onmousedown()onblur() 之前触发,所以如果单击了其中一个菜单div,则该标志将设置在onblur() 中,但如果屏幕上的其他位置被单击,则不会。如果菜单被点击,我会立即从onblur() 返回而不删除菜单,然后等待onclick() 触发,此时我可以安全地删除菜单。

有没有更优雅的解决方案?

代码如下所示:

<div class="menu" onmousedown="setFlag()" onmouseup="doProcessing()">...</div>
<input id="input" onblur="removeMenu()" ... />

var mouseflag;

function setFlag() 
    mouseflag = true;


function removeMenu() 
    if (!mouseflag) 
        document.getElementById('menu').innerHTML = '';
    


function doProcessing(id, name) 
    mouseflag = false;
    ...

【问题讨论】:

【参考方案1】:

onClick 不应替换为 onMouseDown

虽然这种方法有些工作,但两者是根本不同的事件,在用户眼中具有不同的期望。在这种情况下,使用onMouseDown 而不是onClick 会破坏软件的可预测性。因此,这两个事件是不可互换的。

举例说明:当不小心点击一个按钮时,用户期望能够按住鼠标点击,将光标拖到元素外,然后松开鼠标按钮,最终导致没有动作。 onClick 这样做。 onMouseDown 不允许用户按住鼠标不放,而是会立即触发一个动作,对用户没有任何追索权。 onClick 是我们期望在计算机上触发操作的标准。

在这种情况下,请在 onMouseDown 事件上调用 event.preventDefault()onMouseDown 默认会引发模糊事件,在调用preventDefault 时不会这样做。然后,onClick 将有机会被调用。模糊事件仍然会发生,只是在onClick 之后。

毕竟,onClick 事件是 onMouseDownonMouseUp 的组合,当且仅当它们都出现在同一个元素中。

【讨论】:

这对我来说是完美的解决方案,评论完全正确 - 替换 onMouseDown 会混淆用户体验。投了赞成票。 这应该是正确的答案。感谢您发布此内容 值得注意的是,这也有一些轻微的副作用,例如。无法通过在元素内单击来选择文本。想不出有太多这​​样的问题,就是觉得有点好笑。 如果我在onMouseDown 事件上使用event.preventDefault(),则不会调用我的onFocus 事件 焦点位置在许多应用程序中都很重要。标记的解决方案不允许通过回调将焦点恢复到初始输入框。 onBlur 将发生并移除焦点。这个使用event.preventDefault() 的实现确实允许onClick 处理程序将焦点设置到文本框。【参考方案2】:

我遇到了和你一样的问题,我的 UI 完全按照你的描述设计。我通过简单地将菜单项的onClick 替换为onMouseDown 解决了这个问题。我什么也没做;没有onMouseUp,没有标志。这解决了这个问题,让浏览器根据这些事件处理程序的优先级自动重新排序,而无需我做任何额外的工作。

有什么理由说明这对你不起作用?

【讨论】:

这确实有效。我已经在 FF 中对其进行了测试,效果非常好。 它有效。看起来 onmousedownonblur 之前执行,在 Firefox、Chrome 和 Internet Explorer 中测试。 值得注意的是,这确实会自然地改变行为 - 然后在鼠标按下而不是鼠标向上时处理点击交互。对于大多数人来说可能很好(在这种情况下包括自我),但也有一些缺点。最值得注意的是,如果我单击错误,我经常单击然后拖动按钮,这会阻止调用 onclick - 如果按钮执行非纯功能(删除、发布等),您可能希望保留它并使用标志方法。 在你设置 mouseDown 而不是 onClick 的那一刻,可访问性怎么样,你会杀死所有 @ian-macfarlane 下面列出的答案是处理此问题的正确方法。总之...onMouseDownevent.preventDefault()onClick 以及您想要的操作。【参考方案3】:

通过 onfocus 改变 onclick

即使onblur和onclick相处得不是很好,但显然onfocus和yes onblur。因为即使在菜单关闭后,onfocus 仍然对内部单击的元素有效。

我做到了,它奏效了。

【讨论】:

【参考方案4】:

您可以在 onBlur 处理程序中使用 setInterval 函数,如下所示:

<input id="input" onblur="removeMenu()" ... />

function removeMenu() 
    setInterval(function()
        if (!mouseflag) 
            document.getElementById('menu').innerHTML = '';
        
    , 0);

setInterval 函数将从调用堆栈中删除您的 onBlur 函数,添加因为您将时间设置为 0,此函数将在其他事件处理程序完成后立即调用

【讨论】:

setInterval 是个坏主意,您永远不会取消它,因此它将不断运行您的功能,并且很可能导致您的网站使用最大 cpu。如果您打算使用这种技术(我不推荐),请改用setTimeout。让您的应用依赖于某些事件的发生时间是有风险的事情。 鲁滨逊会有危险!危险!未来的比赛条件! 我最初想出了这个解决方案(好吧setTimeout 不是setInterval),但我不得不将它提高到250ms,然后才能以正确的顺序发生。这个错误可能仍然存在于速度较慢的设备上,并且它也会使延迟明显。我尝试了onMouseDown,它工作正常。我想知道它是否也需要触摸事件。 如果你真的想使用onClick,像间隔这样的东西也不错。但是你想要一个带有条件而不是间隔的递归超时,这样它就不会永远运行。这与 Selenium 条件等待使用的模式相同。【参考方案5】:

onmousedown 替换为onfocus。所以当焦点在文本框内时会触发这个事件。

onmouseup 替换为onblur。当您将焦点移出文本框时,onblur 就会执行。

我想这就是你可能需要的。

更新

当你在 onfocus 上执行你的函数时——>移除你将在 onblur 中应用的类并添加你想要在 onfocus 上执行的类

当你执行你的函数 onblur-->删除你将在 onfocus 中应用的类 并添加要在 onblur 上执行的类

我认为不需要标志变量。

更新 2:

您可以使用事件 onmouseout 和 onmouseover

onmouseover - 检测光标何时在其上方。

onmouseout-检测光标何时离开。

【讨论】:

为了清楚起见,我已经编辑了我的问题。该解决方案如何避免设置标志的需要?另外,我在菜单上使用onmousedown()onmouseup(),而不是文本框/输入字段。 我还不能接受这个答案,因为我不知道它是否正确。您能否回应我在上述评论中提出的担忧? 当然,我可以看到你如何使用 onmouseover 和 onmouseout 类似于我目前正在做的事情,当鼠标悬停在菜单上时设置一个标志。但是,我仍然认为您需要在 onmouseover 中设置一个标志,该标志在 onmouseout 中被清除,以便您在单击时知道您是否在菜单上方。你能想出一种不需要设置标志的方法吗? 我能看到你的代码吗...把它放在小提琴里...只要把相关的部分和它完全可以,如果我没有看到结果..只是代码.. 让我们continue this discussion in chat

以上是关于onclick() 和 onblur() 排序问题的主要内容,如果未能解决你的问题,请参考以下文章

清除文本框值 onclick 并显示 onblur

React - 带有 onBlur 事件的 ul 阻止 onClick 在 li 上触发

064_Js常用的五大事件 onclick nochanger onload onsubmit onblur

解决input中智能提示框onblur与onclick冲突的问题

事件(Event)(onclick,onchange,onload,onunload,onfocus,onblur,onselect,onmuse)转载

JavaScript 中的事件onload 加载完成事件-onclick 单击事件-onblur 失去焦点事件-onchange 内容发生改变事件-onsubmit 表单提交事件