触发点击事件需要多长时间?

时间:2019-03-27 08:43:38

标签: javascript html css css3

我尝试创建一个选择框,单击输入框后,其输入将打开。选择其中一项后,下拉菜单应再次关闭。 我想在不使用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的替代解决方案。但是请注意,我主要想集中精力获得该问题的答案,而不是替代解决方案。

2 个答案:

答案 0 :(得分:1)

正如@Mark Ba​​ijens在评论中所说,使用超时是一种不好的做法,因此这是一个非常干净的解决方案。 我使用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。只是对我而言这没有意义,因此请记住这一点,让我们开始吧:)

正在运行的演示>> HERE <<

步骤1-删除CSS的style.visibility部分

所以,剩下的就是这个:

#outer...:hover

步骤2-将#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

步骤3-创建<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

步骤4-在function showElements() { document.getElementById("results").style.visibility = 'visible'; } function hideElements() { document.getElementById("results").style.visibility = 'hidden'; } 元素之外单击时调用hideElements()

input元素之外单击有两种情况:

  • 案例1-我们点击了input包装器中的div
  • 情况2-在输入字段之外单击,但不在#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事件。

如开篇所述,工作示例为>> HERE (codepen.io) <<

答案 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的性能时间表对此进行了调查,但没有发现两个事件之间都有新的渲染。可以看到,结果项已聚焦(轮廓已设置在其上),然后按预期消失。