通过在 Javascript 中单击外部来关闭下拉列表(教程说明)

sal*_*der 5 html javascript web

我试图通过w3schools.com上的教程使用 Javascript 实现打开和关闭下拉菜单的方法。虽然“显示”下拉菜单的功能有效,但关闭它的功能却不起作用。此外,此代码旁边没有解释来解释为什么它应该工作,这使得调试变得困难。

/* When the user clicks on the button, 
toggle between hiding and showing the dropdown content */
function myFunction() {
    document.getElementById("myDropdown").classList.toggle("show");
}

// Close the dropdown menu if the user clicks outside of it
window.onclick = function(event) {
  if (!event.target.matches('.dropbtn')) {

    var dropdowns = document.getElementsByClassName("dropdown-content");
    var i;
    for (i = 0; i < dropdowns.length; i++) {
      var openDropdown = dropdowns[i];
      if (openDropdown.classList.contains('show')) {
        openDropdown.classList.remove('show');
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

因此,我的问题是,

1) 教程中的代码是否应该用于关闭下拉菜单。(已回答)

2)为了让我自己和未来遇到相同教程和问题的新手清楚起见,有人可以澄清这应该如何/为什么起作用吗?(未答复)

编辑(我的尝试):

HTML:

<div class="sharedown">     
    <p onclick="shareVis()" class="sharebtn">&nbsp Share</p>
    <div id="mySharedown" class="sharedown-content">
        <a href="#">Self</a>
        <p>User</p><input type="text" name="user-name" placeholder="Share to">
        <a href="#">Community</a>
    </div> 
</div>
Run Code Online (Sandbox Code Playgroud)

JS:

function shareVis() {
    document.getElementById("mySharedown").className = "show";
}

window.onclick = function(event) {
    if (!event.target.matches('sharebtn')) {

        var sharedowns = document.getElementsByClassName("sharedown-content");
        var i;
        for (i = 0; i < sharedowns.length; i++) {
            var openSharedown = sharedowns[i];
            if (openSharedown.classList.contains('show')) {
                openSharedown.classList.remove('show');
            }
        }
    }   
}
Run Code Online (Sandbox Code Playgroud)

CSS:

/* Share dropdown menu */

p.sharebtn {

    color: darkgrey;
    font-family:calibri;
    padding: 0px;
    margin: 0px;
    font-size: 12;
    border: none;
    cursor: pointer;
    display:    inline; 
}

/* Dropdown button on hover & focus */
p.sharebtn:hover, p.sharebtn:focus {
    color: grey;

}

/* The container <div> - needed to position the dropdown content */

.sharedown {
    position: relative;
    display:    inline-block;   
Run Code Online (Sandbox Code Playgroud)

}

/* Dropdown Content (Hidden by Default) */
.sharedown-content {
    display: none;
    position: absolute;
    background-color:   #f1f1f1;
    min-width:  100px;
    box-shadow: 0 2px 4px 1px #C4E3F5;
    z-index:1; /* place dropdown infront of everything else*/
}

.sharedown-content a { 
color: black;
padding: 5px 5px;
text-decoration: none;
display: block;
}

/* Show the dropdown menu (use JS to add this class to the .dropdown-
content container when the user clicks on the dropdown button) */

.show {display: block;
    position: absolute;
    background-color:   #f1f1f1;
    min-width:  100px;
    box-shadow: 0 2px 4px 1px #C4E3F5;
    opacity: 1;
    z-index:1;}
Run Code Online (Sandbox Code Playgroud)

Thu*_*Tat 7

问题在于shareVis功能。这里

document.getElementById("mySharedown").className = "show";
Run Code Online (Sandbox Code Playgroud)

您正在将#mySharedown类名替换为show. 然后在window.onclick

var sharedowns = document.getElementsByClassName("sharedown-content");
Run Code Online (Sandbox Code Playgroud)

您没有得到任何信息,sharedowns因为您已经将类名替换为show.


您可以将show类添加到classList

document.getElementById("mySharedown").classList.add("show");
Run Code Online (Sandbox Code Playgroud)

或将类名替换为 sharedown-content show

document.getElementById("mySharedown").className = "sharedown-content show";
Run Code Online (Sandbox Code Playgroud)

下面的工作解决方案:

document.getElementById("mySharedown").className = "show";
Run Code Online (Sandbox Code Playgroud)
var sharedowns = document.getElementsByClassName("sharedown-content");
Run Code Online (Sandbox Code Playgroud)
document.getElementById("mySharedown").classList.add("show");
Run Code Online (Sandbox Code Playgroud)

更新

为了防止第二次点击#mySharedown隐藏#mySharedown,你应该click#mySharedown它添加另一个事件并防止它冒泡,像这样

document.getElementById("mySharedown").addEventListener('click',function(event){
    event.stopPropagation();
});
Run Code Online (Sandbox Code Playgroud)

更新包含在工作解决方案中


小智 5

更新 2022 Vanilla Javascript 现在包含一个名为 Node.closest(Node) 的方法来检查事件是否与上层层次结构中的节点匹配。下面是一个在单击时打开下拉菜单并在单击时再次隐藏它的示例,如果在文档外部单击也会隐藏下拉菜单。

const list = document.querySelector('.list')
const btn = document.querySelector('.btn')

btn.addEventListener('click', (e)=> {
  
 list.classList.toggle('hidden')
  e.stopPropagation()
})

document.addEventListener('click', (e)=> {
  if(e.target.closest('.list')) return 
  
  list.classList.add('hidden')

})
Run Code Online (Sandbox Code Playgroud)
.hidden {
  display:none
}
ul {
  background-color: blue;
  
}
Run Code Online (Sandbox Code Playgroud)
<button class="btn">open</button>
<ul class="list hidden">
    <li class="item1">Item 1</li>
    <li class="item2">Item 2</li>
    <li class="item3">Item 3</li>
</ul>
Run Code Online (Sandbox Code Playgroud)