我尝试创建一个选择框,单击输入框后,其输入将打开。选择其中一项后,下拉菜单应再次关闭。 我想在不使用javascript的情况下实现下拉菜单的打开/关闭部分。
html看起来像这样:
<div id="outer">
<input type="text" id="input">
<div id="results">
<div>Test 1 </div>
<div>Test 2 </div>
<div>Test 3 </div>
<div>Test 4 </div>
</div>
</div>
<div id="label">
</div>
单击某个项目后,所选值应显示在#outer
div下方(仅用于演示目的)。
用于将点击事件分配给下拉值的Javascript:
document.querySelectorAll("#results div").forEach(setClick);
function setClick(node) {
node.addEventListener("click", setText.bind(null, node.innerHTML))
}
function setText(t) {
document.getElementById("label").innerHTML = t;
}
现在,我将向您展示我的CSS代码初稿:
#outer {
width: 200px;
position: relative;
}
#input {
width: 100%;
}
#results {
position: absolute;
width: 100%;
display: block;
visibility: hidden;
background-color: white;
}
#results > div:hover {
background-color: lightblue;
cursor: pointer;
}
#outer:focus-within #results, #results:hover {
visibility: visible;
}
这就像一个护身符,但有一点失败:
单击一个项目后,下拉列表不会关闭。这是因为需要#results:hover
选择器,才能在单击某个项目后使下拉菜单保持打开状态。单击将焦点移出输入字段,因此focus-within
选择器不再适用。由于在单击发生之前从输入中移出了焦点,因此当最终单击到达文档时,下拉菜单将隐藏(这是我对问题的理解)。
因此,我使用hover
选择器,只要鼠标位于div上方,它就会迫使div保持打开状态。
您可以在这里进行测试: https://jsfiddle.net/hcetz1og/3/
为此,我的解决方案是过渡,在焦点移开后隐藏下拉菜单:
#outer:not(:focus-within) #results:hover {
visibility: hidden;
transition-property: visibility;
/*use 10 ms and the clicked value in the drop down won't be shown */
transition-delay: 100ms;
transition-timing-function: step-end;
}
当我使用100ms作为延迟时,这在我的机器上有效。如果使用10毫秒,我将再次遇到相同的问题。看来点击事件是“非常”迟才触发的。
随时在这里进行测试: https://jsfiddle.net/hcetz1og/2
问题: 单击事件到达文档需要多长时间?我必须等待一个固定的时间范围,还是延迟取决于每台计算机? 如果是这样,我被迫不使用纯CSS,而我认为必须使用javascript。
修改: 随意发布使用普通CSS的替代解决方案。但是请注意,我主要想集中精力获得该问题的答案,而不是替代解决方案。
答案 0 :(得分:1)
正如@Mark Baijens在评论中所说,使用超时是一种不好的做法,因此这是一个非常干净的解决方案。 我使用JavaScript而不是CSS来渲染下拉列表,因为CSS是您问题的出处。
我不知道您为什么要设置<parent>
<groupId>com.dummy</groupId>
<artifactId>source</artifactId>
<version>0.6-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<dependency>
<groupId>com.dummy</groupId>
<artifactId>source-api</artifactId>
<version>${project.version}</version>
</dependency>
,而不是其他属性,例如innerHTML
。只是对我而言这没有意义,因此请记住这一点,让我们开始吧:)
style.visibility
部分所以,剩下的就是这个:
#outer...:hover
#outer {
width: 200px;
position: relative;
}
#input {
width: 100%;
}
#results {
position: absolute;
width: 100%;
display: block;
visibility: hidden;
background-color: white;
}
#results > div:hover {
background-color: lightblue;
cursor: pointer;
}
事件添加到onfocus
字段只需将函数调用分配给输入的input
属性。 HTML中的所有其他内容都保持不变。
onfocus
<div id="outer">
<input type="text" id="input" onfocus="showElements()">
<div id="results">
<div>Test 1 </div>
<div>Test 2 </div>
<div>Test 3 </div>
<div>Test 4 </div>
</div>
</div>
<div id="label">
</div>
和showElements
函数:hideElements
function showElements() {
document.getElementById("results").style.visibility = 'visible';
}
function hideElements() {
document.getElementById("results").style.visibility = 'hidden';
}
元素之外单击时调用hideElements()
在input
元素之外单击有两种情况:
input
包装器中的div
个#results
包装器内的div
之一上单击在第一种情况中,我们将像这样修改#results
处理程序的分配:
onclick
因此,document.querySelectorAll("#results div").forEach(setClick);
function setClick(node) {
node.addEventListener("click", setTextAndHideElements.bind(null, node.innerHTML));
}
函数现在变为setText
,看起来像这样:
setTextAndHideElements
对于第二种情况(在输入字段之外单击,而不是在function setTextAndHideElements(t) {
document.getElementById("label").innerHTML = t;
hideElements();
}
包装器中的div
之一上单击),我们必须注意是否单击整个页面(#results
元素),并响应以下操作:
document
注意:这将覆盖所有先前分配给document.onclick = function(e) {
if (e.target.id !== 'input'){
hideElements();
}
}
元素的onclick
事件。
答案 1 :(得分:1)
我尝试了另一种无需设置其他JS事件的解决方案。 参见:https://jsfiddle.net/hcetz1og/4/
我给每个result item
的tabindex都设置为“ 0”,以确保这些项目可以聚焦。
然后,我从css中删除了#outer:not()
部分,并用以下命令替换了hover
选择器:#results:focus-within
。单击它们后,我在节点上还打电话给node.blur()
。
摘要: 更改HTML:
<div tabindex="0">Test 1 </div>
更改JS:
function setText(t, node) {
document.getElementById("label").innerHTML = t;
node.blur();
}
更改CSS:
#outer:focus-within #results, #results:focus-within {
visibility: visible;
}
您对此有何看法?我认为应该保持稳定,因为在#results
事件触发到结果项之前已将焦点放在click
div上。
活动顺序应为(根据我的观察):
input focus -> input blur -> item focus -> item click
不确定模糊和聚焦之间的距离是否会导致可见的问题。从理论上讲,必须隐藏结果div并在非常短的时间内再次显示。 但是我用chrome的性能时间表对此进行了调查,但没有发现两个事件之间都有新的渲染。可以看到,结果项已聚焦(轮廓已设置在其上),然后按预期消失。