Onclick()和 onzzy()排序问题

我有一个输入字段,可以打开一个自定义下拉菜单:

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

以下是我的实施方案:

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

问题在于单击菜单时 onclick()事件从来不会触发,因为输入字段的 onblur()首先触发,然后删除菜单,包括 onclick()

我通过将菜单 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;
...
}
86925 次浏览

onmousedown上用 onfocus替换。这样当焦点在文本框中时就会触发这个事件。

onblur代替 onmouseup。当你把焦点从文本框中拿出来的那一刻,就会执行。

我想你可能需要这个。

更新 :

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

还有

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

我看不出有任何标志变量的需要。

更新2:

您可以使用 onmouseout 和 onmouseover 事件

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

Onmouseout -检测光标何时离开。

我也遇到了和你一样的问题我的用户界面设计和你描述的一模一样。我通过简单地将菜单项的 onClick替换为 onMouseDown来解决这个问题。我什么都没做,没有 onMouseUp没有旗子。这解决了这个问题,让浏览器根据这些事件处理程序的优先级自动重新排序,而不需要我做任何额外的工作。

有没有什么原因让你觉得这招不管用?

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

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


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

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

通过 onfocus 更改 onclick

即使在模糊和点击上相处得不是很好,但是很明显在聚焦和是模糊上。因为即使在菜单关闭后,onfocus 对于单击的内部元素仍然有效。

我做到了,而且成功了。

不应该用 onMouseDown代替 onClick

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

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

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

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

onFocus/onBlur是不起泡的事件。然而,确实有一些焦点事件出现了泡沫。这些是 focusinfocusout

现在来看解决方案: 我们将输入和下拉菜单都包装到一个 div 元素中,并将该 div 元素的 tabindex设置为 -1(这样它可以接收焦点/但不会出现在制表符顺序中)。现在,我们将 focusinfocusout的事件侦听器添加到这个 div。由于这些事件确实会冒泡,所以单击 input 元素将触发 div focusin事件(它将打开下拉列表)

现在简洁的部分是点击下拉菜单也会触发 div 的聚焦事件(所以我们基本上保持聚焦,这意味着: focusout/blur永远不会触发,我们的下拉菜单保持打开状态)

你可以试试下面的代码片段(下拉列表只关闭失去焦点-但是如果你想在点击下拉列表时关闭它,只需取消注释 JS 的一行)

const container = document.getElementById("container")
const dropDown = document.getElementById("drop-down")


container.addEventListener("focusin", (event) => {
dropDown.classList.toggle("hidden", false)
})
container.addEventListener("focusout", (event) => {
dropDown.classList.toggle("hidden", true)
})
dropDown.addEventListener("click", (event) => {
console.log("I - the drop down - have been clicked");
//dropDown.classList.toggle("hidden", true);
});
.container {
width: fit-content;
}


.drop-down {
width: 100%;
height: 200px;
border: solid 1px black
}


.hidden {
display: none
}
<div class="container" id="container" tabindex="-1">
<input id="input" />
<div class="drop-down hidden" id="drop-down" > Hi I'm a drop down </div>
</div>

但是有一个问题,如果你想把你的下拉菜单添加到标签顺序中,在你的下拉菜单中有按钮,或者一般在下拉菜单中有一个元素,这样可以获得焦点。因为这样一来,单击就会首先给出下拉焦点中的元素。这会触发容器 div 失去焦点,从而关闭下拉列表,这样焦点事件就不能进一步冒泡,因此也就不能触发容器上的 focusin

我们可以通过稍微扩展 focusout事件侦听器来解决这个问题。

新的事件侦听器如下:

container.addEventListener("focusout", (event) => {
dropDown.classList.toggle("hidden", !container.matches(":hover"))
})

我们基本上说: “如果有人在上面徘徊,不要关闭下拉菜单”(这个解决方案只考虑了鼠标的使用; 但是在这种情况下,这是好的,因为这个方法试图修复的问题只有在使用鼠标时才会出现,当选择/通过下拉菜单时,一切从一开始就运行良好)

我找到的一个适合我的理想解决方案是简单地在 onBlur 函数中添加一个超时。我使用了250ms,这为我的模糊事件提供了流畅的行为,并允许我的 onClick 在 onBlur 之前触发。我使用这个示例作为参考 https://erikmartinjordan.com/onblur-prevents-onclick-react