Javascript body OnClick

10

我正在学习Javascript,尝试创建一个简单的下拉菜单。我想要实现与Google主页顶部菜单中的“更多”和“设置”下拉菜单相同的功能。特别是当你点击菜单以外的区域时,菜单会消失。

在Javascript的hideMenus函数中,我需要加入什么代码才能在屏幕上任意位置点击时隐藏可见的ul元素?

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
<html xmlns="http://www.w3.org/1999/xhtml">  

<head>  
<meta content="text/html; charset=utf-8" http-equiv="Content-Type" />  
<title>Untitled 1</title>  

<style type="text/css">  
a  
{  
    color:blue;  
}  

.info ul.submenu  
{  
    border: solid 1px #e0e0e0;  
    background-color: #fff;  
    position: absolute;  
    padding: 0;  
    z-index: 2;  
    display: none;  
}  

.info ul.submenu li  
{  
    display: block;  
    border-top: solid 1px #e0e0e0;  
    margin: 0px 10px 0 10px;  
}  

.info ul.submenu li a  
{  
    display: block;  
    padding: 7px 0px 6px 0;  
    color: #1177ee;  
    cursor:pointer;  
}  

</style>  

<script type="text/javascript">  

function hideMenus()
{
//TODO
}

function menu(id) {     
    var myLayer = document.getElementById(id);     

    myLayer.onblur = function() {       
        myLayer.style.display = 'none';   
    };   

    if (myLayer.style.display == "none" || myLayer.style.display == "") {     
        myLayer.style.display = "block";     
    } else {     
        myLayer.style.display = "none";     
    }     
}  

</script>  
</head>  

<body onclick="hideMenus();">  
<div class="info">     
     Some Text Boom A <a  onclick="menu('id1');">Link</a> | More text    
     <a onclick="menu('id2');">Another Link</a> | more text    
     <ul id="id1" class="submenu">     
       <li><a href="dfhdfh">A1</a></li>     
       <li><a href="aetjetjsd">A2 This is Long</a></li>     
       <li><a href="etetueb">A3</a></li>     
     </ul>     
    <ul id="id2" class="submenu">     
       <li><a href="dfhdfh">B1</a></li>     
       <li><a href="aetjetjsd">B2</a></li>     
       <li><a href="etetueb">B3</a></li>     
     </ul>     
  </div>    
</body>  
</html>   

我不想使用jQuery。


6
感谢您的投票:“我不想使用jQuery”。 - Richard H
3个回答

1

看起来你的设置已经相当不错了。你可能会遇到一些事件冒泡问题(更多信息,请参阅PPK的事件顺序文章)。这似乎超出了你当前问题的范围,所以我将给你你所要求的内容:

hideMenus()
{
    var uls = document.getElementsByTagName('ul'), i;
    for (i = 0; i < uls.length; i++)
    {
        if (uls[i].className === 'submenu' && uls[i].style.display !== 'none')
        {
            uls[i].style.display = 'none';
        }
    }
}

首先,我们获取页面上所有的<ul>。然后,我们循环遍历它们,检查是否为子菜单以及当前是否显示。如果两者都为真,则隐藏它。

这段代码有几个缺点:

  • 如果ul有多个类(class="animal submenu"),则它将无法隐藏菜单
  • 它将浏览页面上的所有<ul>。这并不是非常高效,但这是没有跨浏览器支持getElementsByClass的唯一方法。

这些不是很大的缺点,特别是如果您只是用它来学习javascript,并且如果您严格控制您的代码(即没有其他开发人员在上面工作)。总的来说,这是一个很好的起点。

在未来,我建议使用addEvent - 这是一个相当常见的函数,它允许您向元素添加事件处理程序,而无需使用onclick="..."。有几种不同的实现方式,但从您的角度来看,它们(几乎)都是相同的。这里是Dean Edwards's VersionJohn Resig's Version的链接。
祝你好运!

糟糕!好发现。已修复,加一。 - Ryan Kinal

0

这是我们在网页应用程序中使用的下拉菜单逻辑:

<html>
<head>
    <title></title>
</head>
<body>
    <div style="position:relative;width:250px">
      <a id="link" href="javascript:" onclick="showDiv(this)">Show menu</a>
      <ul id="entries" style="display:none;background:#DEF;padding:0;margin:0">
        <li>item 1</li>
        <li>item 2</li>
      </ul>
      <input id="inp" style="position:absolute;left:-30px;width:0" />
    </div>

    <script>
        function showDiv(lnk){
            var entries = document.getElementById('entries'),
                inp = document.getElementById('inp'),
                nh = 'data-nohide';
            //show the entries
            entries.style.display = 'block';
            entries.removeAttribute(nh);
            inp.focus();
            //if mouse over, can't close it
            entries.onmouseover = function(){ 
                this.setAttribute(nh, true);
                inp.focus();
            }; 
            //if mouse out, can close it
            entries.onmouseout  = function(){ 
                this.removeAttribute(nh);
            };
            entries.onclick = function(e){
                //code when the user clicks on the menu...
                alert((e.target||e.sourceElement).innerHTML);
                this.style.display = 'none';
            };
            //if the user press ESC
            inp.onkeyup = function(e){
                if(e.keyCode === 27){
                    this.style.display = 'none';
                    this.removeAttribute(nh);
                }else{
                    //do something else with other keys(ie:down, up, enter)...
                    inp.focus();
                }
            };
            //click somewhere else input onblur
            inp.onblur = function(){
                if(!entries.getAttribute(nh)){
                    entries.style.display = 'none';
                    entries = inp = null;
                }
            };
        }
    </script>
</body>
</html>

诀窍在于使用具有focusinput字段,当它失去焦点时触发onblur并关闭菜单。

mouseovermouseout用于防止用户单击菜单项时触发onblur

要像链接上的打开/关闭一样具有切换效果,我想需要两个互相隐藏的链接。


-1

如果在body上放置onclick,您可以在任何地方捕获点击。由于JavaScript事件传播模型,如果您在任何元素上单击任何位置并且不阻止事件传播,则它将到达body并隐藏菜单。

因此,基本上这意味着您想捕获body onclick并使其隐藏菜单,因此当您单击页面的任何区域时,它将关闭菜单。

但是,这会隐藏一些不必要的行为-当您单击显示菜单的按钮时,菜单将显示,然后很快隐藏(当事件到达body时)。为了防止这种情况,您需要在单击显示菜单的按钮时停止事件传播(您可以在我下面发布的代码中看到它是如何工作的)。该代码显示了您需要触摸以使其正常工作的位置。

// this function stops event e or window.event if e is not present from 
// propagating to other elements.
function stop_event(e) {
   if(!e) {
      e = window.event;
   }
   if (e.stopPropagation) e.stopPropagation();
   e.cancelBubble = true;
   if (e.preventDefault) e.preventDefault();
   e.returnValue = false;
   return false;
}

// now you just hide all the menus in your hideMenus
function hideMenus()
{
    //pseudocode!
    for all visible menus - hide // or if you want you can hide all menus, 
                                 // the hidden will remain hidden
}

现在是重要的部分。

function menu(id) {     
    // your stuff here
    stop_event(); // this will stop the event going down to the body 
                  // and hiding it after showing it
                  // this means it will not flicker like: show-hide
}  

最后是针对整个UL元素的操作:

//partly pesudocode
ul.onclick = function() { stop_event(); }

再次解释一下这个功能:

1. 首先,将hideMenu函数挂钩到body.onclick上。这意味着如果我们不停止事件,它将始终隐藏菜单。

2. 当您单击菜单按钮时,会显示菜单,然后我们停止事件传播到body。这样,body.onclick就不会触发,我们打开菜单后不会立即隐藏它。

3. ul.onclick表示当我们单击菜单时,菜单不会自动隐藏(尽管如果您希望在单击菜单本身时隐藏菜单,则可以删除此部分)。


你正在使用参数e定义stop_event,但是你没有使用事件参数调用它? - Marcel Korpel
E不是必需的,正如您所看到的。而且如果您仔细查看代码,它确实做了操作者想要的事情——如果您在屏幕上的任何地方单击(如果他指的是网页本身,而不是操作系统或浏览器框架),则隐藏菜单,因为他将hideMenu挂钩到了body click事件上。至于最后一部分……我现在会进行编辑,再读一遍后,它似乎真的很愚蠢。 - bisko
糟糕,忽略了 onclick="hideMenus();" 部分。由于 window.event 仅受 IE 支持,因此 e 是必需的。但是,在使用 DOM 级别 0 的内联事件处理程序(在非 IE 浏览器中)时,event 接口作为参数传递给 包装函数,因此 e不可访问的。还可以查看 JSBin 进行尝试。因此,无法通过这种方式停止事件冒泡。关于解释:确实,现在这样更清晰了。 - Marcel Korpel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接