簡體   English   中英

當用戶在下拉菜單之外單擊時如何隱藏下拉菜單

[英]How to hide a dropdown when the user clicks outside of it

下面是我正在使用的輸入下拉列表的簡化版本。

其作用的基本摘要是:如果您專注於輸入,則會出現一個下拉列表。 如果您單擊下拉列表中的選項之一,該選項將填充輸入並且下拉列表消失。 這是使用onfocus和我稱為dropdown();的函數實現的dropdown(); undropdown(); .

我處於兩難境地,當有人點擊其他地方時,我無法使下拉菜單消失。 如果我使用onblur ,它會成功隱藏下拉列表,但是如果您單擊一個選項,它不會填充輸入,這是因為onblur函數首先運行,因此, input(); 函數不會運行,因為下拉列表已經隱藏。

如果您在 body 標簽或其他父標簽上放置onclick ,它會將onfocus視為單擊,在那里運行的是dropdown(); 函數然后是undropdown(); 立即運行,因此下拉菜單永遠不會出現,因為功能重疊。

我很感激幫助弄清楚如何對函數進行排序,以便它們以正確的順序執行而不會相互重疊。

JSFiddle在這里可用

 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"; }
 .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; }
 <div class="drop"> <input type="text" name="class" placeholder="Class" onfocus="dropdown(0)"/> <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>

PS:除了上述問題之外,我希望您能提出編輯建議以獲得更好的標題,以便遇到類似問題的人可以更容易地找到它。

在這種情況下,在onblur你可以調用一個函數來觸發undropdown(0); 在一個非常小的 setTimeout 幾乎立即之后。 像這樣:

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

HTML

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

不需要其他更改。

 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); }
 .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; }
 <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>

你可以做的下拉可聚焦與tabindex ,並在輸入的blur事件偵聽器只隱藏下拉如果焦點沒有去下拉(見當的onblur時,我怎么能找出哪些元素焦點去

<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>

接受的答案是一種幼稚且不可靠的方法。 我在復雜的應用程序中遇到了一個難以捕捉的錯誤,因為我使用了setTimeout來提供約 200 毫秒的延遲,以便瀏覽器可以在模糊事件發生之前處理下拉單擊。 雖然它在我測試過的每個設置上都運行良好,但一些用戶確實遇到了問題,尤其是機器速度較慢的用戶。

正確的方法是測試relatedTargetfocusout的事件:

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

relatedTarget用於focusout包含一個元素的參考,這是接收焦點。 到目前為止,這在我測試過的每個瀏覽器中都可靠地工作(我沒有測試 IE10 及更低版本,只測試了 IE11 和 Edge)。

W3Schools 有一個很好的例子來說明如何創建自定義下拉列表: https : //www.w3schools.com/howto/howto_custom_select.asp

這是該示例中處理焦點的方式:

全局點擊處理程序處理下拉列表之外的點擊: document.addEventListener("click", closeAllSelect); . 因此,只要用戶單擊文檔中的任意位置,所有下拉菜單都會關閉。

但是當用戶選擇下拉列表的一個元素時,點擊事件被e.stopPropagation(); 選擇處理程序的內部。

這樣,您就不需要計時器解決方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM