onmouseout と setTimeout

JavaScriptで単純なドロップダウンメニューを作ろうとして、onmouseoutの挙動ではまったのでメモ。

ドロップダウンメニューのHTMLは次の通り。

<div id="nav">
  <div id="menu1" class="menu">
    <span id="menulabel1" class="label">Menu Label</span>
    <ul id="menulist1" class="menuitem">
      <li><a href="#item1">Menu item 1</a></li>
      <li><a href="#item2">Menu item 2</a></li>
      <li><a href="#item3">Menu item 3</a></li>
      <li><a href="#item4">Menu item 4</a></li>
      <li><a href="#item5">Menu item 5</a></li>
    </ul>
  </div>
</div>

 
“menulabel1” にマウスオーバーした時に “menulist1” が表示されるようにして、”meulist1″ からポインタが外れた時に非表示にしたい。

CSS は次の通り。

#nav .menu .label {
    border: 1px solid #999;
    display: block;
    padding: 0.25em;
    width: 10em;
}
#nav .menu ul.menuitem {
    border: 1px solid #999;
    display: none;
    list-style-type: none;
    margin: 0;
    padding: 0;
    width: 10.5em;
}
#nav .menu .menuitem li {
    background: transparent;
    margin: 0;
    padding: 0.25em;
    width: 10em;
}
#nav .menu .menuitem li:hover {
    background: #eee;
}
#nav .menu .menuitem li a {
    color: #000;
    text-decoration: none;
}

最初に考えたのは、”menulabel1″ の onmouseover で下のような showMenu() を、”menulist1″ の onmouseout で下のような hideMenu() を実施するようにすること。

var elMenu     = document.getElementById("menulabel1");
var elMenuItem = document.getElementById("menulist1");

var showMenu = function() {
    elMenuItem.style.display = "block";
};

var hideMenu = function() {
    elMenuItem.style.display = "none";
};

addListener(elMenu, "mouseover", showMenu);
addListener(elMenuItem, "mouseout", hideMenu);

(addListener 関数は、SNIPPLR にある Add Event Listener を使った。)

このコードだと、表示されたドロップダウンメニューをポイントした時に onmouseout イベントが発生して、メニューがすぐに消えてしまう(なぜかは分からないが)。

なので、hideMenu() に setTimeout を指定し、”menulist1″ の mouseover に clearTimeout を実行して回避した。

var elMenu     = document.getElementById("menulabel1");
var elMenuItem = document.getElementById("menulist1");
var timer;

var showMenu = function() {
    elMenuItem.style.display = "block";
};

var hideMenu = function() {
    timer = setTimeout(function(){
        elMenuItem.style.display = "none";
    }, 1)
};

addListener(elMenu, "mouseover", showMenu);
addListener(elMenuItem, "mouseover", function() { clearTimeout(timer); });
addListener(elMenuItem, "mouseout", hideMenu);

JavaScriptのサンプル全体は次のような感じ。

// Cross-browser implementation of element.addEventListener()
// <a href="http://snipplr.com/view/561/add-event-listener/">http://snipplr.com/view/561/add-event-listener/</a>
var addListener = function(element, type, expression, bubbling) {
    bubbling = bubbling || false;

    if(window.addEventListener) { // Standard
        element.addEventListener(type, expression, bubbling);
        return true;
    } else if(window.attachEvent) { // IE
        element.attachEvent('on' + type, expression);
        return true;
    } else return false;
};

var dropDownMenu = function() {
    var elMenu     = document.getElementById("menulabel1");
    var elMenuItem = document.getElementById("menulist1");
    var timer;

    var showMenu = function() {
        clearTimeout(timer);
        elMenuItem.style.display = "block";
    };

    var hideMenu = function() {
        timer = setTimeout(function(){
            elMenuItem.style.display = "none";
        }, 1)
    };

    addListener(elMenu, "mouseover", showMenu);
    addListener(elMenu, "mouseout", hideMenu);
    addListener(elMenuItem, "mouseover", showMenu);
    addListener(elMenuItem, "mouseout", hideMenu);
    addListener(elMenuItem, "click", hideMenu);
};

addListener(window, "load", dropDownMenu);

意図した動きにはなったけれど、何か腑に落ちない。mouseout イベントが発生する理由とか、もっといいやり方があるんじゃないかとか。

onmouseout と setTimeout

Don’t ask users what features should be added

「ソフトウェアを作っている会社やそのユーザーはやたらと機能を追加したがるのだけど、そこの会社は一切ユーザーの声を聞かないらしいですよ。何をしているかというと、そのソフトを使って一番成功しているユーザーのところに行ってひたすら観察するらしいです。それを見ながらうまくいくためにはどういう機能をつけるべきかを考える、というのがその会社のポリシーです」

どの機能をつけるべきか、はユーザーに聞いてはいけない – IDEA*IDEA ~ 百式管理人のライフハックブログ ~

(English translation)
Software companies and the users want to add features, but the company never hear their users requests. What they are doing is that they visit their most successful user and concentrate to observe what the user is doing with their software. And then they think what sort of feature leads their users to success. This is the company’s design policy.

Don’t ask users what features should be added