我有一个输入字段,可以显示自定义下拉菜单。我想要以下功能:
这是我的实施:
输入字段有一个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;
...
}
答案 0 :(得分:121)
我遇到与你完全相同的问题,我的UI设计与你描述完全一样。我通过简单地用onMouseDown替换菜单项的onClick来解决问题。我什么都没做;没有onMouseUp,没有标志。这解决了这个问题,让浏览器根据这些事件处理程序的优先级自动重新排序,而不需要我做任何额外的工作。
为什么这对你没有用呢?
答案 1 :(得分:10)
onClick
不应替换为onMouseDown
。
虽然这种方法行之有效,但两者在本质上是不同的事件,在用户眼中具有不同的期望。在这种情况下,使用onMouseDown
而非onClick
会破坏软件的可预测性。因此,这两个事件是不可互换的。
为了说明:用户不小心单击按钮时,希望能够按住鼠标单击,将光标拖到元素外,然后释放鼠标按钮,最终不会采取任何措施。 onClick
执行此操作。 onMouseDown
不允许用户按住鼠标,而是立即触发操作,而无需用户追索。 onClick
是我们期望在计算机上触发操作的标准。
在这种情况下,请在event.preventDefault()
事件上调用onMouseDown
。默认情况下,onMouseDown
默认情况下会导致模糊事件,而在调用preventDefault
时不会这样做。然后,onClick
将有机会被调用。仅在onClick
之后,模糊事件仍然会发生。
毕竟,onClick
事件是onMouseDown
和onMouseUp
的组合,只要且仅当它们都出现在同一元素内即可。
答案 2 :(得分:4)
将onmousedown
替换为onfocus
。因此,当焦点位于文本框内时,将触发此事件。
将onmouseup
替换为onblur
。当您从文本框中取出焦点时,onblur将会执行。
我想这就是你可能需要的。
<强>更新强>:
执行onfocus函数时 - >删除将在onblur中应用的类并添加要在onfocus上执行的类
和
执行onblur函数时 - >删除将在onfocus中应用的类 并添加要在onblur上执行的类
我认为不需要标志变量。
更新2:
您可以使用事件onmouseout和onmouseover
onmouseover - 当光标在它上面时检测。
onmouseout - 当光标离开时检测。
答案 3 :(得分:2)
更优雅(但可能性能较差)的解决方案:
使用document.onclick
代替使用输入的onblur删除菜单,而onblur
会在input.onclick
之后触发。
但是,这也意味着在单击输入时删除菜单,这是不希望的行为。使用event.stopPropagation()
设置{{1}},以避免将点击次数传播到文档点击事件。
答案 4 :(得分:0)
通过onfocus更改onclick
即使onblur和onclick不能相处得很好,但显然onfocus和是onblur。因为即使菜单关闭后,onfocus对于单击内部的元素仍然有效。
我做了,但确实有效。
答案 5 :(得分:-3)
您可以在setInterval
处理程序中使用onBlur
函数,如下所示:
<input id="input" onblur="removeMenu()" ... />
function removeMenu() {
setInterval(function(){
if (!mouseflag) {
document.getElementById('menu').innerHTML = '';
}
}, 0);
}
setInterval
函数将从调用堆栈中删除onBlur
函数,添加因为您将时间设置为0,此函数将在其他事件处理程序完成后立即调用