segunda-feira, 3 de outubro de 2011

Ocultar menu ao clicar fora do DIV (Javascript)

Quando criamos páginas dinâmicas, geralmente utilizamos o posicionamento do mouse para mostrar e ocultar menus, através de combinação das propriedades display e visibility com o evento onMouseOver do Javascript.
Mas o que fazer quando não há mouse? Esse é o caso da programação de páginas para tablets e smartphones. O funcionamento de menus nesses aparelhos dependerá principalmente da função onClick do Javascript. Basta "clicar" (ou dedilhar) no link e o menu aparece.

Mas agora nos deparamos com um problema: se alguém clicar por engano em um link, e abrir um menu, como é possível ocultá-lo novamente?
A solução mais simples e intuitiva é clicar em qualquer área fora do menu. Porém, não existe em Javascript um evento onClickOutsideElement. Esta é uma dúvida que encontrei em vários fóruns, e as soluções mais sugeridas são:
  • utilizar bibliotecas prontas como jQuery ou MooTools;
  • funções em Javascript que analisam o tamanho e a posição do menu e comparam com a posição do click;
  • funções mais avançadas em Javascript, que verificam eventos, elementos-filhos (childNodes) e elementos-pais (parentNodes).
Mas consegui montar uma solução bem mais simples, graças à uma variável global que chamei de flag no código abaixo.
Funciona assim: ao clicar no link Show Menu, é executada a função menuShow que mostra a DIV "menu" e atribui à variável flag o valor "0".
Agora, observe duas coisas:
  • a tag Body possui um evento onClick que executa a função checkMenu;
  • o link Show Menu faz parte da tag Body.
Portanto, clicar no link Show Menu também significa clicar em uma parte da tag Body. Logo, a função checkMenu também será executada.
Neste momento, o valor de flag é "0", e a função passa direto pelo if. Em seguida, verifica que o elemento (DIV "menu") está visível e atribui à flag o valor "1".
Para ocultar o menu, simplesmente clique em qualquer área longe do link Show Menu. A função checkMenu será executada, mas agora o valor de flag é "1" e o if será executado, ocultando a DIV "menu" e retornando o valor de flag para "0".




Hide menu when click outside DIV (Javascript)

When creating dynamic pages, we usually get the mouse position to show and hide menus, through a combination of display and visibility properties with the onMouseOver Javascript event.
But what to do when there is no mouse? This is the case of programming pages for tablets and smartphones. The operation of menus on those devices usually requires the onClick Javascript function. Just "click" (or finger) on the link and the menu appears.

But now we face a problem: if someone clicks on a link by mistake, and menu is shown, how to hide it back?
The simplest and most intuitive solution is to click on any area outside the menu. However, there is no onClickOutsideElement event in Javascript. This is a question that I found on various forums, and the suggested solutions were:
  • to use existing libraries like jQuery or MooTools;
  • Javascript functions that analyze the size and position of the menu and compare with the position of the click;
  • more advanced functions in Javascript, which analyze events, childNodes and parentNodes.
But I managed to build a much simpler solution, thanks to a global variable called flag on the code below.
It works like this: when you click on Show Menu, the function menuShow is executed, showing the DIV "menu" and assigning the value "0" to the variable flag.
Now, two things must be observed:
  • the Body tag has an onClick event which executes the function checkMenu;
  • the Show Menu link is part of the Body tag.
Therefore, to click the Show Menu link also means to click on part of the Body tag. Thus, the function checkMenu is executed too.
At this moment, the flag value is "0" and the function skips the if. Next, it checks that the element (DIV "menu") is visible and assigns the value "1" to flag.
To hide the menu, simply click on any area away from the Show Menu link. The checkMenu function is executed, but now the flag value is "1" and the if will be executed, hiding the DIV "menu" and returning the flag value to "0".



CÓDIGO (CODE)

<html>
<head>

<style type="text/css">

#menu table td {background-color: #c0c0c0;
    border: 2px solid brown;}
#menu table td:hover {background-color: #ffff55;
    border:2px solid #c0c0c0;}
#menu a {color: blue;
    text-decoration: none;}
</style>

<script type="text/javascript">

var flag;
function checkMenu(element)
{    if(flag==1)
     {    menuHide(element);
          flag=0;
          exit;
     }
if(document.getElementById(element).style.display=="block")
     {flag=1;}
}

function menuShow(element,horizontal,vertical)

{document.getElementById(element).style.display = "block";
     flag=0;
}

function menuHide(element)

{document.getElementById(element).style.display = "none";}
</script>
</head>

<body onclick="checkMenu('menu');">

<a href="javascript:void(0);" onclick="menuShow('menu');">Show Menu</a>
<div id="menu" style="display:none;">
  <table>
  <tr><td><a href="">Link 1</a></td></tr>
  <tr><td><a href="">Link 2</a></td></tr>
  <tr><td><a href="">Link 3</a></td></tr>
  <tr><td><a href="http://www.google.com" target="_blank">Link to Google on new page</a></td></tr>
  </table>
</div>
</body>
</html>

2 comentários:

  1. Olá Eduardo,

    Parabéns pela artigo, usei a lógica do flag, porém ao clicar na DIV ela também desaparecia, fiz uma adaptação de outro artigo. No sei caso como é um menu e há ação ocorre não se nota.

    Tirei do body, ficando assim:

    document.onclick=evento;

    function evento(e){
    var target = (e && e.target) || (event && event.srcElement);
    alert(target.id);
    checkParent(target);
    }
    function checkParent(t){
    while(t.parentNode){
    if(t==document.getElementById('minhadiv')){
    return false
    }
    t=t.parentNode
    }
    menuHide(XXXXX)

    ResponderExcluir