ところが、どんどん押していくうちに、押した所と違う内容が開いてしまいます。
-- 希望の動作 --
・メニューを押すとその真下に内容が表示され、もう一回同じメニューを押すと内容が非表示になる
・内容を表示した状態で、別のメニューを押すと、内容を自動で非表示にし、押したメニューの内容を表示する
・内容が表示されている状態で、なにもないところをクリックしたら、内容を閉じる
一番良い回答を下さった方のみに150P差し上げます。
はてなの文字数制限にひっかかるので別の場所にアップしたコード↓
http://1st.geocities.yahoo.co.jp/gl/barreko00/view/20110610
同時に二つ開くことはないと判断しました。
function $stl(id) { return document.getElementById(id).style ; } var active = '' ; function show(id) { if (active) $stl(active+'-menu').display = 'none' ; if (id != active) { $stl(id+'-menu').display = 'block' ; active = id ; } else active = '' ; }
何もないところをクリックはよく分からなかったので保留。
問題はココですね。
if (active) { document.getElementById(active+'-btn').onclick=function(){show(active)}; var activeElm = document.getElementById(active+'-menu'); activeElm.style.display='none'; }
このifが成立した時にonclickはどうなるかというと、
function(){show(active)}
です。
おそらく期待している動作は
function(){show('id1')}
などでしょうけれど、そうではないです。
ちなみに、hideの場合も
function(){show('id1')}
ではなく
function(){show(id)}
となっているのですが、こちらはクロージャがあるので大丈夫ですね。
正しく動作するコードが必要でしたら追記いたします。
追記:
document.getElementById(active+'-btn').onclick=function(){show(active)};
↑の部分を以下のように変更。
document.getElementById(active+'-btn').onclick=( function(active){ return function(){show(active)} } )(active);
一応、動作確認してます。ご想定の動作と違うようでしたらご指摘ください。
自分もアマグラマなので正確には説明できないのですが、JavaScriptの場合、functionごとにスコープがあるような感じです。
ですので、activeはグローバル変数として書き換えられてしまい正しく動作せず、idはfunctionの中での値を保持しているため正しく動作する、ということみたいです。
変更後のコードでは、引数として取らせてクロージャを作る感じでしょうか。
コードお願いできますか。
うーん。これは変数のスコープが良く理解できていないということなのか・・・
クロージャでちょっと調べてみたら、じっくり読まないと理解できなそうですね
同時に二つ開くことはないと判断しました。
function $stl(id) { return document.getElementById(id).style ; } var active = '' ; function show(id) { if (active) $stl(active+'-menu').display = 'none' ; if (id != active) { $stl(id+'-menu').display = 'block' ; active = id ; } else active = '' ; }
何もないところをクリックはよく分からなかったので保留。
確認しました。「何もないところ・・」以外は、希望通りの動作です。
何もないところをクリック、というのは「画面のメニュー以外部分をクリックしたら・・・」という意味で、ポップアップを使っているサイトではよくある実装のアレです。
ご希望の動作か分かりませんが……
<body onclick="show(null)">
body 、あるいは希望の範囲を div 等でくくって onclick を仕込む。
function $stl(id) { return document.getElementById(id).style ; } var active = '' ; var mnClk = false ; function show(id) { if (!id && mnClk) { mnClk = false ; return ; } if (active) $stl(active+'-menu').display = 'none' ; if (id != active) { $stl(id+'-menu').display = 'block' ; active = id ; mnClk = true ; } else active = '' ; }
jQueryで実装してみました。
onclick="show('id1')"のように要素毎に書くのは面倒だと思うので消しました。
表示/非表示はtoggle()に任せるのが楽です。
id1-btn、id1-menuのようにidで管理するのではなく、classとdivなどで階層を作ってボタンとメニューを管理すれば、要素を追加するだけで(id1~とも書かずに)すっきりと書けます。
demo: http://jsfiddle.net/L8JpD/
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script> <script> //http://q.hatena.ne.jp/1307682576 $(function() { $('[id^="id"][id$="-btn"]').click(function() { var self = $(this); var ac = $('.active'); if (ac.length) { if (ac.attr('id') !== self.attr('id')) { ac.trigger('click'); } } $('#' + self.attr('id').replace(/btn$/, 'menu')).toggle(200); self.toggleClass('active'); }); $('body').click(function(e) { if ($(e.target).is('*:not([id^="id"][id$="-btn"]):not([id^="id"][id$="-menu"])')) { $('.active').trigger('click'); } }); }); </script> <style> body { width: 2000px; height: 2000px; } .active { background-color: orange; } [id^="id"][id$="-menu"] { background-color: aliceblue; } </style> </head> <body> <span id="id1-btn">[その1]</span><br /> <div id="id1-menu" style="display:none;cursor:pointer">--内容1--</div> <span id="id2-btn">[その2]</span><br /> <div id="id2-menu" style="display:none;cursor:pointer">--内容2--</div> <span id="id3-btn">[その3]</span><br /> <div id="id3-menu" style="display:none;cursor:pointer">--内容3--</div> <span id="id4-btn">[その4]</span><br /> <div id="id4-menu" style="display:none;cursor:pointer">--内容4--</div> </body> </html>
参考までに jQuery UI - Accordion というのもあります。
質問の際にコードの断片を貼るのではなく、回答者がコピペですぐ確認できるコードのほうが、問題を共有しやすいですよ。
のようなサービスを積極的に利用しましょう。
あと回答者に対して、サンプルの提示を求めれば確認が楽になるかと。
参考になるアドバイスありがとうございます。
このデモに使っているサイトいいですね
言っておけばよかったのですが、現在prototype.jsを使っており
jqueryは競合が恐いので利用を避けています。
確認しました。「何もないところ・・」以外は、希望通りの動作です。
何もないところをクリック、というのは「画面のメニュー以外部分をクリックしたら・・・」という意味で、ポップアップを使っているサイトではよくある実装のアレです。