如何在用户点击其下方时隐藏下拉列表

时间:2016-12-08 13:58:20

标签: javascript html css input drop-down-menu

以下是我正在使用的输入下拉列表的简化版本。

它的作用的基本概要是:如果您专注于输入,则会出现一个下拉列表。如果单击下拉列表中的某个选项,该选项将填充输入并且下拉列表将消失。这是使用onfocus和我称为dropdown();undropdown();的函数实现的。

我处于两难境地,当有人点击其他地方时,我无法让下拉列表消失。如果我使用onblur,它会成功隐藏下拉列表,但是如果单击某个选项,它就不会填充输入,这是因为onblur函数首先运行,因此, <{1}}函数无法运行,因为下拉列表已被隐藏。

如果您在正文标记或其他父标记上放置input();,则会将onclick视为点击,其中onfocus函数运行dropdown(); {1}}立即运行,因此函数重叠后永远不会出现下拉列表。

我很感激帮助找出如何订购这些功能,以便它们以正确的顺序执行而不会相互重叠。

JSFiddle可用here.

&#13;
&#13;
undropdown();
&#13;
function input(pos) {
  var dropdown = document.getElementsByClassName('drop');
  var li = dropdown[0].getElementsByTagName("li");
  document.getElementsByTagName('input')[0].value = li[pos].innerHTML;
  undropdown(0);
}
function dropdown(pos) {
  document.getElementsByClassName('content')[pos].style.display = "block"
}
function undropdown(pos) {
  document.getElementsByClassName('content')[pos].style.display = "none";
}
&#13;
.drop {
  position: relative;
  display: inline-block;
  vertical-align: top;
  overflow: visible;
}
.content {
  display: none;
  list-style-type: none;
  border: 1px solid #000;
  padding: 0;
  margin: 0;
  position: absolute;
  z-index: 2;
  width: 100%;
  max-height: 190px;
  overflow-y: scroll;
}
.content li {
  padding: 12px 16px;
  display: block;
  margin: 0;
}
&#13;
&#13;
&#13;

PS:除了上述问题之外,我还是希望有关编辑的建议,以便为这个问题获得更好的标题,以便遇到类似问题的人可以更轻松地找到它。

4 个答案:

答案 0 :(得分:2)

在这种情况下,在onblur上,您可以调用一个函数,该函数几乎立即在非常小的setTimeout之后触发undropdown(0);。像这样:

function set() {
  setTimeout(function(){ 
    undropdown(0);
  }, 100);
}

<强> HTML

<input type="text" name="class" placeholder="Class" onfocus="dropdown(0)" onblur="set()" />

无需进行其他更改。

&#13;
&#13;
function input(pos) {
  var dropdown = document.getElementsByClassName('drop');
  var li = dropdown[0].getElementsByTagName("li");

  document.getElementsByTagName('input')[0].value = li[pos].innerHTML;
  undropdown(0);
}

function dropdown(pos) {
  document.getElementsByClassName('content')[pos].style.display= "block"
}

function undropdown(pos) {
  document.getElementsByClassName('content')[pos].style.display= "none";
}

function set() {
  setTimeout(function(){ 
    undropdown(0);
  }, 100);
}
&#13;
        .drop {
            position: relative;
            display: inline-block;
            vertical-align:top;
            overflow: visible;
        }

        .content {
            display: none;
            list-style-type: none;
            border: 1px solid #000; 
            padding: 0;
            margin: 0;
            position: absolute;
            z-index: 2;
            width: 100%;
            max-height: 190px;
            overflow-y: scroll;
        }

        .content li {
            padding: 12px 16px;
            display: block;
            margin: 0;
        }
&#13;
   <div class="drop">
        <input type="text" name="class" placeholder="Class" onfocus="dropdown(0)" onblur="set()" />
        <ul class="content">
            <li onclick="input(0)">Option 1</li>
            <li onclick="input(1)">Option 2</li>
            <li onclick="input(2)">Option 3</li>
            <li onclick="input(3)">Option 4</li>
        </ul>
    </div>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

您可以使用tabindex使下拉列表具有焦点,并且在输入的blur事件侦听器中,如果焦点未转到下拉列表,则仅隐藏下拉列表(请参阅When onblur occurs, how can I find out which element focus went to?)< / p>

<ul class="content" tabindex="-1"></ul>
input.addEventListener('blur', function(e) {
  if(!e.relatedTarget || !e.relatedTarget.classList.contains('content')) {
    undropdown(0);
  }
});

function input(e) {
  var dropdown = document.getElementsByClassName('drop');
  var li = dropdown[0].getElementsByTagName("li");
  document.getElementsByTagName('input')[0].value = e.target.textContent;
  undropdown(0);
}
[].forEach.call(document.getElementsByTagName('li'), function(el) {
  el.addEventListener('click', input);
});
function dropdown(pos) {
  document.getElementsByClassName('content')[pos].style.display = "block"
}
function undropdown(pos) {
  document.getElementsByClassName('content')[pos].style.display = "none";
}
var input = document.getElementsByTagName('input')[0];
input.addEventListener('focus', function(e) {
  dropdown(0);
});
input.addEventListener('blur', function(e) {
  if(!e.relatedTarget || !e.relatedTarget.classList.contains('content')) {
    undropdown(0);
  }
});
.drop {
  position: relative;
  display: inline-block;
  vertical-align: top;
  overflow: visible;
}
.content {
  display: none;
  list-style-type: none;
  border: 1px solid #000;
  padding: 0;
  margin: 0;
  position: absolute;
  z-index: 2;
  width: 100%;
  max-height: 190px;
  overflow-y: scroll;
  outline: none;
}
.content li {
  padding: 12px 16px;
  display: block;
  margin: 0;
}
<div class="drop">
  <input type="text" name="class" placeholder="Class" />
  <ul class="content" tabindex="-1">
    <li>Option 1</li>
    <li>Option 2</li>
    <li>Option 3</li>
    <li>Option 4</li>
  </ul>
</div>

答案 2 :(得分:0)

可接受的答案是一种幼稚且不可靠的方法。我在复杂的应用程序中遇到了难以捕获的错误,因为我使用了setTimeout来提供〜200ms的延迟,以便浏览器可以在发生模糊事件之前处理下拉单击。尽管它在我测试过的每个设置上都能很好地运行,但某些用户确实遇到了问题,特别是计算机速度较慢的用户。

正确的方法是在relatedTarget事件上测试focusout

input.addEventListener('focusout', function(event) {
  if(!isDropdownElement(event.relatedTarget)) {
    // hide dropdown
  }
});
relatedTarget

focusout包含一个element reference,该焦点正在获得关注。到目前为止,这在我测试过的所有浏览器中都可以可靠地工作(我没有测试IE10及更低版本,只有IE11和Edge)。

答案 3 :(得分:0)

W3Schools有一个很好的示例,说明如何创建自定义下拉列表: https://www.w3schools.com/howto/howto_custom_select.asp

在该示例中,焦点的处理方式如下:

全局点击处理程序可处理下拉列表document.addEventListener("click", closeAllSelect);之外的点击。因此,只要用户单击文档中的任意位置,所有下拉列表都将关闭。

但是,当用户选择下拉列表的元素时,点击事件将由选择句柄内的e.stopPropagation();停止。

这样,您就不需要计时器解决方法。