【问题标题】:Closing dropdown by clicking outside in Javascript (tutorial clarification)通过在 Javascript 中单击外部来关闭下拉列表(教程说明)
【发布时间】:2018-11-01 02:31:03
【问题描述】:

我试图通过 w3schools.com 上的 this 教程实现使用 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');
      }
    }
  }
}

因此,我的问题是,

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>

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

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;   

}

/* 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;}

【问题讨论】:

  • 请提供 HTML 以告诉您确切的问题在哪里?因为 w3schools 中的示例功能齐全
  • 浏览器中的调试控制台是什么意思?
  • 控制台没有错误
  • 你能添加你的css吗?
  • document.getElementById("mySharedown").className = "show"; 覆盖类名。它不再有sharedown-content 类,所以当window.onclick 触发时,sharedowns 变量将为空。

标签: javascript html web


【解决方案1】:

问题在于shareVis 函数。这里

document.getElementById("mySharedown").className = "show";

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

var sharedowns = document.getElementsByClassName("sharedown-content");

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


您可以将show 类添加到classList
document.getElementById("mySharedown").classList.add("show");

或者用sharedown-content show替换类名

document.getElementById("mySharedown").className = "sharedown-content show";

以下工作解决方案:

function shareVis() {
    //document.getElementById("mySharedown").className = "sharedown-content show";
    document.getElementById("mySharedown").classList.add("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');
            }
        }
    }
}

document.getElementById("mySharedown").addEventListener('click',function(event){
    event.stopPropagation();
});
#mySharedown{
  display: none;
  border: 1px solid black;
}

#mySharedown.show {
  display: block;
}
<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>

更新

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

document.getElementById("mySharedown").addEventListener('click',function(event){
    event.stopPropagation();
});

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

【讨论】:

  • 下拉菜单现在保持打开状态;但是当我点击任何地方时它会关闭,包括它的内部。有什么帮助吗?
  • 你想在再次点击分享按钮后关闭它吗?
  • 我希望它在单击后关闭,除了在菜单本身内。
  • 更新运行良好。现在我的下拉菜单正在按我的意愿工作。但是,我仍然不太明白 function(event) 和包含的 for 循环是如何产生这种效果的(也是我最初问题的一部分)。也许我会深入研究一下文档。
【解决方案2】:

在这里我留下另一个“简短”的例子,我在自己的代码中实现了,但很容易理解。

.tw-hidden 是一个类 "display: none"

window.onclick = function(event) {
        let customDropdownsEl = document.querySelectorAll(".custom-dropdown");
        let liContainerEl = event.target.querySelector(".custom-dropdown");
    
        customDropdownsEl.forEach(el => el.parentNode !== event.target && !el.classList.contains("tw-hidden") && el.classList.add("tw-hidden"));
        event.target.matches('.custom-dropdown-container') && liContainerEl.classList.toggle("tw-hidden");
}

【讨论】:

    【解决方案3】:

    该示例功能齐全,应该可以工作。复制以下代码:

    /* 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 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');
              }
            }
          }
        }
     .dropbtn {
            background-color: #3498DB;
            color: white;
            padding: 16px;
            font-size: 16px;
            border: none;
            cursor: pointer;
        }
        
        .dropbtn:hover, .dropbtn:focus {
            background-color: #2980B9;
        }
        
        .dropdown {
            position: relative;
            display: inline-block;
        }
        
        .dropdown-content {
            display: none;
            position: absolute;
            background-color: #f1f1f1;
            min-width: 160px;
            overflow: auto;
            box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
            z-index: 1;
        }
        
        .dropdown-content a {
            color: black;
            padding: 12px 16px;
            text-decoration: none;
            display: block;
        }
        
        .dropdown a:hover {background-color: #ddd}
        
        .show {display:block;}
        
        <h2>Clickable Dropdown</h2>
        <p>Click on the button to open the dropdown menu.</p>
        
        <div class="dropdown">
        <button onclick="myFunction()" class="dropbtn">Dropdown</button>
          <div id="myDropdown" class="dropdown-content">
            <a href="#home">Home</a>
            <a href="#about">About</a>
            <a href="#contact">Contact</a>
          </div>
        </div>

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多