ページ上のどこでも良い場所をクリックしてメニューを消す方法

[新着] Webテンプレートを仮オープンしました



0   名前: minx : 2007/01/22(月) 11:33  ID:i2Krktoq sub-.B
ポップアップメニューを表示し、その後、その他の何らかのオブジェクトをクリックした際に、そのメニューを消したいのです。(Windowsのエクスプローラetcで、オブジェクトを右クリックすると、ポップアップメニューが表示され、他のオブジェクトをクリックするまでメニューが表示されていますが、それと同じ動作を実現したいのです。)

下記のコードでは、メニューの表示までが出来ます。
topmenu(t_m0102)、mainmenu(m_m0102)のonBlurイベントを捉えようとしましたが、メインメニューの項目を選択(クリック)した後でないと、onBlurが動かない事が分かりました。
どうすれば、表示したメニュー以外のオブジェクトが選択された時に、メニューを消す事ができますでしょうか。
お知恵を拝借下さい。

尚、メニューの消去には、参考用として、hideMenu関数を用意しています。

------------------------------------------

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML><HEAD>
<TITLE>MJ QM/SOP/WI</TITLE>
<META http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<META content="IBM WebSphere Studio Homepage Builder Version 10.0.1.0 for Windows" name="GENERATOR">
<META http-equiv="Content-Style-Type" content="text/css">

<STYLE type=text/css>
<!--
.topmenu {position:absolute}

.mainmenu {display:none;
position:absolute;
visibility:hidden;
z-index:1000;}

.mainmenu a {display:block;
text-align:left;
text-indent:5px;
text-decoration:none;
font-size:12px;
color:black;
background-color:#cccccc;
line-height:20px;
border-bottom:solid 1px #777777;
border-right:solid 1px #777777;
width:150;}

.mainmenu a:hover {background-color:303070;
color:white;}

-->
</STYLE>

<script type="text/javascript">
<!--
var tmTop, tmHeight, tmLeft;
//--------------------------------------------------------------------------------------------------
function showMenu(idnum){
tmTop=document.getElementById('t_m' + idnum).offsetTop;
tmHeight=document.getElementById('t_m' + idnum).offsetHeight;
tmLeft=document.getElementById('t_m' + idnum).offsetLeft;
document.getElementById('m_m' + idnum).style.top = tmTop + tmHeight;
document.getElementById('m_m' + idnum).style.left=tmLeft;
document.getElementById('m_m' + idnum).style.display="block";
document.getElementById('m_m' + idnum).style.visibility="visible";
}

function hideMenu(idnum){
document.getElementById('m_m' + idnum).style.display="none";
document.getElementById('m_m' + idnum).style.visibility="hidden";
}
/ -->
</Script>

</HEAD>

<!-- ----------------------------------- -->
<BODY>


<DIV class="topmenu" id="t_m0102" style="top:100; left:100" onClick="showMenu('0102')">
<A href="javascript:void(0);">トップメニュー1</A>
</DIV>
<!-- ----------------------------------- -->
<DIV class="mainmenu" id="m_m0102">
<a href="javascript:void(0);" id="mmc0102-00">メインメニュー項目1</A>
<a href="javascript:void(0);" id="mmc0102-01")">メインメニュー項目2</A>
</DIV>

<div class="topmenu" style="top:200; left:100" onclick="hideMenu('0102')">
<A href="javascript:void(0);">メニューを消す</A>
</div>

</BODY>
</HTML>

【備考】
OS:Windows XP Professional / ブラウザ:IE6のみ、という環境です。

1   名前: JAB : 2007/01/22(月) 11:33  ID:MqlHe6Xi sub-gm
参照:http://hp.xrea.jp/m/s/36.html

2   名前: minx : 2007/01/22(月) 11:33  ID:ophBpHbZ sub-Ax
ありがとうございます。
なるほど、<BODY>で左クリックならメニューを閉じる、右クリックで、もしメニューが閉じていたら開く、というロジックですね。

それを参考に以下のように作ってみました。
しかし、私の場合、メニューを開くのは、左クリックなのです。そして、<BODY>タグのイベントの方が後に呼ばれるようなので、メニューが開かないという結果になってしまうようです。

任意のリンクを左クリック->メニュー表示
それ以外の適当な場所を左クリック->メニュー消去
という事は果たして出来ますでしょうか....


-----------------------------

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML><HEAD>
<TITLE>MJ QM/SOP/WI</TITLE>
<META http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<META content="IBM WebSphere Studio Homepage Builder Version 10.0.1.0 for Windows" name="GENERATOR">
<META http-equiv="Content-Style-Type" content="text/css">

<STYLE type=text/css>
<!--
.topmenu {position:absolute;}

.mainmenu {display:none;
position:absolute;
visibility:hidden;
z-index:1000;}

.mainmenu a {display:block;
text-align:left;
text-indent:5px;
text-decoration:none;
font-size:12px;
color:black;
background-color:#cccccc;
line-height:20px;
border-bottom:solid 1px #777777;
border-right:solid 1px #777777;
width:150;}

.mainmenu a:hover {background-color:303070;
color:white;}

-->
</STYLE>

<script type="text/javascript">
<!--
var tmTop, tmHeight, tmLeft;
//--------------------------------------------------------------------------------------------------
function showMenu(idnum){
alert('showmenu');
tmTop=document.getElementById('t_m' + idnum).offsetTop;
tmHeight=document.getElementById('t_m' + idnum).offsetHeight;
tmLeft=document.getElementById('t_m' + idnum).offsetLeft;
document.getElementById('m_m' + idnum).style.top = tmTop + tmHeight;
document.getElementById('m_m' + idnum).style.left=tmLeft;
document.getElementById('m_m' + idnum).style.display="block";
document.getElementById('m_m' + idnum).style.visibility="visible";
}

function hideMenu(idnum){
alert('hidemenu');
if(document.getElementById('m_m' + idnum).style.visibility=="visible") {
document.getElementById('m_m' + idnum).style.display="none";
document.getElementById('m_m' + idnum).style.visibility="hidden";
}
}
/ -->
</Script>

</HEAD>

<!-- ----------------------------------- -->
<BODY onclick="hideMenu('0102');">

<DIV class="topmenu" id="t_m0102" style="top:100; left:100" onClick="showMenu('0102')">
<A href="javascript:void(0);">トップメニュー1</A>
</DIV>
<!-- ----------------------------------- -->
<DIV class="mainmenu" id="m_m0102">
<a href="javascript:void(0);" id="mmc0102-00">メインメニュー項目1</A>
<A href="javascript:void(0);" id="mmc0102-01" )">メインメニュー項目2</A>
</DIV>

<div class="topmenu" style="top:200; left:100" onclick="hideMenu('0102')">
<A href="javascript:void(0);">メニューを消す</A>
</div>

</BODY>
</HTML>

3   名前: minx : 2007/01/22(月) 11:33  ID:ophBpHbZ sub-Ax
出来ました。
<BODY>のonclickイベントが生じるときに、メニューを開こうとして生じたイベントなのか、そうでないのかを識別するための「wm」というグローバル変数を用意しました。
ヒントのお陰です。ありがとうございました。

この後、サブメニューを追加して行きます。

-------------------------------


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML><HEAD>
<TITLE>MJ QM/SOP/WI</TITLE>
<META http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<META content="IBM WebSphere Studio Homepage Builder Version 10.0.1.0 for Windows" name="GENERATOR">
<META http-equiv="Content-Style-Type" content="text/css">

<STYLE type=text/css>
<!--
.topmenu {position:absolute;}

.mainmenu {display:none;
position:absolute;
visibility:hidden;
z-index:1000;}

.mainmenu a {display:block;
text-align:left;
text-indent:5px;
text-decoration:none;
font-size:12px;
color:black;
background-color:#cccccc;
line-height:20px;
border-bottom:solid 1px #777777;
border-right:solid 1px #777777;
width:150;}

.mainmenu a:hover {background-color:303070;
color:white;}

-->
</STYLE>

<script type="text/javascript">
<!--
var tmTop, tmHeight, tmLeft, wm;
//--------------------------------------------------------------------------------------------------
function showMenu(idnum){
wm=1;
tmTop=document.getElementById('t_m' + idnum).offsetTop;
tmHeight=document.getElementById('t_m' + idnum).offsetHeight;
tmLeft=document.getElementById('t_m' + idnum).offsetLeft;
document.getElementById('m_m' + idnum).style.top = tmTop + tmHeight;
document.getElementById('m_m' + idnum).style.left=tmLeft;
document.getElementById('m_m' + idnum).style.display="block";
document.getElementById('m_m' + idnum).style.visibility="visible";
}

function hideMenu(idnum){
if(wm!=1){
if(document.getElementById('m_m' + idnum).style.visibility=="visible") {
document.getElementById('m_m' + idnum).style.display="none";
document.getElementById('m_m' + idnum).style.visibility="hidden"}
}
wm=0;
}
/ -->
</Script>

</HEAD>

<!-- ----------------------------------- -->
<BODY onclick="hideMenu('0102');">

<DIV class="topmenu" id="t_m0102" style="top:100; left:100" onclick="showMenu('0102')">
<A href="javascript:void(0);">トップメニュー1</A>
</DIV>
<!-- ----------------------------------- -->
<DIV class="mainmenu" id="m_m0102" onclick="wm=1">
<a href="javascript:void(0);" id="mmc0102-00">メインメニュー項目1</A>
<A href="javascript:void(0);" id="mmc0102-01" )">メインメニュー項目2</A>
</DIV>

<div class="topmenu" style="top:200; left:100" onclick="hideMenu('0102')">
<A href="javascript:void(0);">メニューを消す</A>
</div>

</BODY>
</HTML>

4   名前: minx : 2007/01/22(月) 11:33  ID:ophBpHbZ sub-Ax
サブメニューも追加出来ました。
一応ご報告しておきます。

-----------------------------

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML><HEAD>
<TITLE>MJ QM/SOP/WI</TITLE>
<META http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<META content="IBM WebSphere Studio Homepage Builder Version 10.0.1.0 for Windows" name="GENERATOR">
<META http-equiv="Content-Style-Type" content="text/css">

<STYLE type=text/css>
<!--
.topmenu {position:absolute;}

.mainmenu {display:none;
position:absolute;
visibility:hidden;
z-index:1000;}

.mainmenu a {display:block;
text-align:left;
text-indent:5px;
text-decoration:none;
font-size:12px;
color:black;
background-color:#cccccc;
line-height:20px;
border-bottom:solid 1px #777777;
border-right:solid 1px #777777;
width:200;}

.mainmenu a:hover {background-color:303070;
color:white;}

.submenu {position:absolute;
visibility:hidden;}

.submenu a {width:300;}

-->
</STYLE>

<script type="text/javascript">
<!--
var tmTop, tmHeight, tmLeft, wm, prev;
//--------------------------------------------------------------------------------------------------
function showMenu(idnum){
if(prev!="0000"){
document.getElementById('s_m' + prev).style.visibility="hidden";
document.getElementById('mmc' + x).style.background="#cccccc";
document.getElementById('mmc' + x).style.color="black";
}
wm=1;
tmTop=document.getElementById('t_m' + idnum).offsetTop;
tmHeight=document.getElementById('t_m' + idnum).offsetHeight;
tmLeft=document.getElementById('t_m' + idnum).offsetLeft;
document.getElementById('m_m' + idnum).style.top = tmTop + tmHeight;
document.getElementById('m_m' + idnum).style.left=tmLeft;
document.getElementById('m_m' + idnum).style.display="block";
document.getElementById('m_m' + idnum).style.visibility="visible";
}

function hideMenu(idnum){
if(wm!=1){
if(document.getElementById('m_m' + idnum).style.visibility=="visible") {
document.getElementById('m_m' + idnum).style.display="none";
document.getElementById('m_m' + idnum).style.visibility="hidden"}
}
wm=0;
}

//--------------------------------------------------------------------------------------------------
function showSubmenu(y){
if(prev!="0000"){
document.getElementById('s_m' + prev).style.visibility="hidden";
document.getElementById('mmc' + x).style.background="#cccccc";
document.getElementById('mmc' + x).style.color="black";
}
x=y.slice(3, 10);
m_id = (x.slice(0,4));
document.getElementById('mmc' + x).style.background="#303070";
document.getElementById('mmc' + x).style.color="white";
document.getElementById('s_m' + x).style.left=document.getElementById('m_m' + m_id).offsetWidth;
document.getElementById('s_m' + x).style.top=document.getElementById('mmc' + x).offsetTop;
document.getElementById('s_m' + x).style.visibility="visible";
prev=x;
}

//--------------------------------------------------------------------------------------------------

/ -->
</Script>

</HEAD>

<!-- ----------------------------------- -->
<BODY onload='prev="0000"' onclick="hideMenu('0102');">

<DIV class="topmenu" id="t_m0102" style="top:100; left:100" onclick="showMenu('0102')">
<A href="javascript:void(0);">トップメニュー1</A>
</DIV>
<!-- ----------------------------------- -->
<DIV class="mainmenu" id="m_m0102" onclick="wm=1">
<a href="javascript:void(0);" id="mmc0102" onMouseover="showSubmenu(this.id)">メインメニュー項目1</A>
<div class="submenu" id ="s_m0102">
<a href="link.htm">サブメニュー項目1-1</a>
<a href="link.htm">サブメニュー項目1-2</a>
<a href="link.htm">サブメニュー項目1-3</a>
</div>

<A href="javascript:void(0);" id="mmc0102-01" onMouseover="showSubmenu(this.id)">メインメニュー項目2</A>
<div class="submenu" id ="s_m0102-01">
<a href="link.htm">サブメニュー項目2-1</a>
<a href="link.htm">サブメニュー項目2-2</a>
<a href="link.htm">サブメニュー項目2-3</a>
<a href="link.htm">サブメニュー項目2-4</a>
<a href="link.htm">サブメニュー項目2-5</a>
<a href="link.htm">サブメニュー項目2-6</a>
</div>
</DIV>

</BODY>
</HTML>

5   名前: 匿名 : 2007/01/22(月) 11:33  ID:4N1QN0WR sub-kJ
body 要素に click イベントを付ける。

・DOM Events なら event.target
・IE なら event.srcElement

でどのノードがクリックされたかを見る。a 要素がクリックされたなら関連ノードの表示を切り替え、それ以外なら元に戻す。

そんな馬鹿げた数の id 属性なんて疲れるだけだと思うが。


あと、CSS 文法の範疇なのだが、

> width:150;

> background-color:303070;

> document.getElementById('m_m' + idnum).style.top = tmTop + tmHeight;
> document.getElementById('m_m' + idnum).style.left=tmLeft;

> style="top:100; left:100"
> style="top:200; left:100"

これらは全部 CSS エラー。要確認。

6   名前: minx : 2007/01/22(月) 11:33  ID:ophBpHbZ sub-Ax
ありがとうございます。

確認しましたが、ご指摘いたいだ中で

background-color:303070; 

以外の部分は、きちんと機能しているようでした。

7   名前: 匿名 : 2007/01/22(月) 11:33  ID:4N1QN0WR sub-kJ
>>6
それはブラウザの CSS エラー修正機能が働いているから。たとえば、Firefox や Opera のエラーコンソールで確認してみれ。

CSS のルール上、top、left、width、height は、0 以外の場合は必ず単位を付けねばならない。CSS を利用するスクリプトも、このルールに従う必要がある。

エラーが生じたプロパティは、本来は全て無視されねばならない。たとえば、(拡張で操作できるなら)Firefox の超厳格モードで見てみれ。エラーが生じたプロパティは、仕様に従い全て無視されるはずだ。

HTML、CSS のルールを知らないと、まともなスクリプトは書けないぞ。

8   名前: minx : 2007/01/22(月) 11:33  ID:ophBpHbZ sub-Ax
なるほど、エラー修正機能が働いているのですね。

私の場合は、スレッドの最初にも書きましたとおり、IE6だけという環境です。
従って、実質上問題ないという状況ではありますが、勉強になりました。

9   名前: 匿名 : 2007/01/22(月) 11:33  ID:4N1QN0WR sub-kJ
CSS を正しく書くことと、使用ブラウザは関係ないと思うよ。間違った CSS を書くこと自体に問題があるわけで。

つか自分の投稿を見返して、すごく嫌味っぽかったと思った。ごめん。

10   名前: 匿名 : 2007/01/22(月) 11:33  ID:4N1QN0WR sub-kJ
で、別解として >>5 でも書いたが、たとえば

document./*@cc_on @if (@_jscript) attachEvent('on' + @else@*/
addEventListener(/*@end@*/ 'click',
    function (e) {
        var t = e.target || event.srcElement;
        
        if (t.nodeName == 'A') {
            // この a 要素に対応する要素の表示・非表示
        } else {
            // 全メニューの非表示
        }
    }, true)


のようにすれば、イベントリスナ登録が 1 回で済む(いちいち onclick を埋め込む必要などない)。また、メニューはリスト構造になることが多く、ul/ol 要素などでマークアップしている「はず」だから、階層構造を辿れば id に頼らずとも関連ブロックを識別できる。

なお完全に余談だが、Firefox、Opera ならば

document.addEventListener ('DOMNodeInserted',
    function (e) {
        var t = e.target
        
        if (t.nodeName == 'DIV' && t.className == 'submenu') {
            t.style.display = 'none';
        }
    }, true)


のように、ノード出現時点で(ページの load 完了を待たずとも)初期化できる。この時点で非表示にしたノードを Array にでも保持しておけば、全メニューの非表示も簡単にできる。

11   名前: minx : 2007/01/22(月) 11:33  ID:u7OKXWvF sub-vK
アドバイスありがとうございます。

折角示していただいたコードですが、私の理解を遙かに超えております。

保存版にして、そのうちゆっくりと消化します.....

一覧へ戻る