144

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

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

这是我的实现:

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

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

我通过将菜单 div 拆分为事件并在鼠标按下时设置全局标志来解决问题,该onclick()标志onmousedown()onmouseup()鼠标抬起时被清除,类似于此答案中的建议。因为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;
    ...
}
4

5 回答 5

212

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

有什么理由为什么这对你也不起作用?

于 2015-03-10T12:36:41.067 回答
105

onClick不应替换为onMouseDown.

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

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

在这种情况下,调用event.preventDefault()事件onMouseDown。默认情况下会导致模糊事件,并且在调用onMouseDown时不会这样做。preventDefault然后,onClick将有机会被召唤。模糊事件仍然会发生,仅在onClick.

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

于 2019-08-23T16:41:43.480 回答
2

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

替换onmouseuponblur。当您将焦点从文本框中移出时,onblur 将执行。

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

更新

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

当您执行 onblur 函数时--> 删除您将在 onfocus 中应用的类并添加您希望在 onblur 中执行的类

我认为不需要标志变量。

更新 2:

您可以使用事件 onmouseout 和 onmouseover

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

onmouseout - 检测光标何时离开。

于 2013-07-21T05:31:28.987 回答
0

通过 onfocus 更改 onclick

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

我做到了,它奏效了。

于 2018-01-09T16:38:19.427 回答
-7

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

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

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

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

于 2015-11-12T03:56:08.893 回答