• ベストアンサー

イベントハンドラを完全に外部化にしたい

イベントハンドラをなんとか、完全に外部ファイルにしたいと考えています。 <ul><li> <a href="a.html" onmouseout="MM_swapImgRestore()" onmouseover="MM_swapImage('Image1','','../ig/c1.gif',1)"> <img src="../ig1.gif" alt="aaa" name="Image1" id="Image1" /></a></li> <li> <a href="b.html" onmouseout="MM_swapImgRestore()" onmouseover="MM_swapImage('Image2','','../ig/c2.gif',1)"> <img src="../ig2.gif" alt="bb" name="Image2" id="Image2" /></a></li> ・ ・ ・ </ul> サイトのナビ部分のソースです。この中にあるonmouseout、やonmouseoverを外部ファイルにして、 <ul><li> <a href="a.html"><img ~></li> <a href="b.html"><img ~></li>・ ・ ・ </ul>というすっきりした形にできないものでしょうか… イベント登録する関数を作って、ページのonloadで実行しておく という感じかな…と考えていたりするんですが… どのように記述すればよいか お知恵をお貸しください。 ※MM_swapImgRestoreやMM_swapImageはすでに外部化済です

質問者が選んだベストアンサー

  • ベストアンサー
noname#30818
noname#30818
回答No.8

細かいことは抜きにして <a href="a.html" onmouseout="MM_swapImgRestore()" onmouseover="MM_swapImage('Image1','','../ig/c1.gif',1)"> <a href="b.html" onmouseout="MM_swapImgRestore()" onmouseover="MM_swapImage('Image2','','../ig/c2.gif',1)"> これが <script> window.onload = function(){ var ul = document.getElementById('ABC') var a = ul.getElementsByTagName('a') for(var i = 0;i < a.length;i++){ a[i].onmouseover = over a[i].onmouseout = out } } function over(){ //引数を作成する処理 MM_swapImage(name,'',src,1) } function out(){ MM_swapImgRestore() } </script> <a href="a.html">..... <a href="b.html">...... となるわけです。 ここまでは良いですよね。 つぎにMM_swapImageで使っている引数をover内で作るのです。 その引数は、 ・1番目はimgのname属性値 ・3番目はimgのsrc属性値 と仮定する。 src属性値には ・<body>にあるものは→  ig/c/navi1.gif ・<head>にあるものは→  ig/c/s/navi1.gif javascriptでは ・imgのname属性値は☆.getAttribute('name')で取得可能。 ・imgのsrc属性値はdocument.☆.srcで取得可能。 これを使って引数を作ります。 そこでsrcを取得しnaviをs/naviに変更する ところがimg.srcで取得できる値が相対パスである保証はないので取得したsrc値を一旦”/”で分割しその最後だけを使うとファイル名だけが残る。 src = src.split('/') src = src[src.length - 1] //src == navi1.gif これにs/を追加するのですが、naviの前に入れたいのでnaviをs/naviに置換する。 src=src.replace(/navi/,"s/navi") //src == s/navi1.gif これの先頭に"../ig/c/"を加えると3番目の引数となる。 src="../ig/c/"+src //src == ../ig/c/s/navi1.gif これを事前に確認したい時は bodyに結果を表示すれば画像を用意しなくても動作だけ確認できる。 document.body.appendChild(document.createTextNode("<img src="+ src + " name=" + img.getAttribute('name') + "/>\n\r")) HTMLでは改行文字は空白になるのでbody{white-space:pre;}を入れる。 こうするとoverは function over(){ var img = this.getElementsByTagName('img')[0] var url = img.src url = url.split('/') url = '../ig/c/'+url[url.length-1].replace(/navi/,'s/navi') MM_swapImage(img.getAttribute('name'),'',url,1) } となりHTMLは <a href="a.html"><img src="../ig1.gif" alt="bb" name="Image1" id="Image1" /></a> <a href="b.html"><img src="../ig2.gif" alt="bb" name="Image2" id="Image2" /></a> となりますね? これで <a href="a.html" onmouseout="MM_swapImgRestore()" onmouseover="MM_swapImage('Image1','','../ig/c1.gif',1)"> <a href="b.html" onmouseout="MM_swapImgRestore()" onmouseover="MM_swapImage('Image2','','../ig/c2.gif',1)"> と同じ結果が期待できますね。 nameを取るにはMM_swapImageでname値を使っているので削ることができませんのでMM_swapImageを改造するか、新しい関数を作るかover内で同じような処理をするしかありませんね。 そこで function over(e){ if(!e){ var e = event }//イベントを取る var img = this.getElementsByTagName('img')[0]//参照番号で参照 var url = img.src url = url.split('/') if(e.type == "mouseover"){ img.src = "../ig/c/'+url[url.length-1].replace(/navi/,'s/navi')//"/s"が入る }else if(e.type == "mouseout"){ img.src = "../ig/c/'+url[url.length-1]//"/s"が入らない } } これで1つの関数で画像の切り替えができるわけですよね。 するとここが for(var i = 0;i < a.length;i++){ a[i].onmouseover = over a[i].onmouseout = over } となりHTMLは <a href="a.html"><img src="../ig1.gif" alt="bb" /></a> <a href="b.html"><img src="../ig2.gif" alt="bb" /></a> となるわけですね。

etu007
質問者

お礼

ありがとうございます!!! 無事に動かせました。とてもとても…助かりました。 蛇足ですが、今まで ig/c/s/navi1.gif~などは body onload="MM_preloadImages()で 読み込んでいたんですが、これはもうなくても 問題ないでしょうか? やっている限り問題なさそうなのですが… しばらくお待ちしてコメントいただけなければ 締めさせていただきます。 ありがとうございました。 ※MM_preloadImagesの内容については NO2さんへの補足をご覧ください。

その他の回答 (10)

  • venzou
  • ベストアンサー率71% (311/435)
回答No.11

>エラーの方ですが >ライン:17 >文字:1 エラーが再現できました。 imgタグを含まないaタグがある場合にエラーが出るようです。 配列が空の場合のIF文の条件判断について、ちょっと勘違いしてました、ごめんなさい。 16行目と28行目を修正して下さい。 >if(img){ if(img.length > 0){ これで大丈夫だと思います。

etu007
質問者

お礼

お手数おかけしました! ありがとうございます!! ほんとに助かりました~!!!!

  • venzou
  • ベストアンサー率71% (311/435)
回答No.10

>>#他に良回答でてますので、そちらを使って頂いた方が良いかな。 >そうですよね… >すいません ちょっと言葉足らずだったかもしれないので補足しますが、調べるのがめんどくさいからこう書いたわけではなく、他の回答で解決しているなら、こちらの話題は引っ張らない方がよいかな?と思ったので書きました。悪い意味に取らないで下さいね。 エラーに関してはWindowsXP IE6で試しましたがこちらではエラーは出ませんでした。謎ですね。エラーが出てるソースをそのまま使うのは良くないので、とことん追究するか、使わないかのどちらかだと思います。 エラーの原因を追究するなら、 >クリックするとエラー内容が表示されます… この内容を補足願います。(行番号とか出てませんか?) こちらではエラーが再現しないので、解決出来るかわかりませんが、可能な限り調べますよ。 もちろん、こちらのソースを使わないという選択もありですので、判断はお任せします。 ---------------------- ついでに、横槍で回答しますが・・・ >body onload="MM_preloadImages()で これはプレロードの為の物ですので、なくても動きます。 プレロードしておくと、画像の切り替えがスムーズになります。 逆にプレロードしていないと、最初の画像の入れ替え時に、画像を読みにいくので、少し切り替えに時間が掛かるかもしれません。(2回目以降はキャッシュされるので問題ないと思います。) ローカルで開いている場合は、画像を開くのは一瞬なので、違いは分からないと思います。WEB上にアップロードしてから、違いを確認してみてください。(違いを確認する時は、事前にキャッシュをクリアして下さい。) 違いが気にならないようなら、なくても良いと思います。

etu007
質問者

お礼

ご丁寧にありがとうございます。 venzouさんのは、venzouさんので やり方をマスターしておきたい…という気持ちで おたずねしました。 >body onload="MM_preloadImages()の件は、ありがとうございました エラーの方ですが ライン:17 文字:1 コード:0(ゼロだと思います) となっていました。 でも問題なく作動していました。なぞです。

  • venzou
  • ベストアンサー率71% (311/435)
回答No.9

>エラー’0.src’はNullまたはオブジェクトではありません #7のプログラムを再度、コピペして確認してみましたが、こちらの環境ではエラーは出ませんでした。 気になるようなら、調べてみますので、ブラウザの種類、エラーが出るタイミング、エラーの場所などもう少し詳しい情報をお願いします。 #他に良回答でてますので、そちらを使って頂いた方が良いかな。

etu007
質問者

補足

#他に良回答でてますので、そちらを使って頂いた方が良いかな。 そうですよね… すいません 一応どのタイミングかはお伝えしておきます。 ブラウザはIE6です タイミングとしてはサイトを開いた直後。 リロードしても同様です。 エラー表示はページ下のタスクバー部分です。 リンク先が表示されるところです。 そこにページでエラーが発生しました… となります。そこで三角形のびっくりマークを クリックするとエラー内容が表示されます… なぞです。 あまり労力が必要であれば、締切させていただきますので。 特に問題なし、とでもご記載いただけますか。 よろしくお願いします。

  • venzou
  • ベストアンサー率71% (311/435)
回答No.7

><body>にあるものは→  ig/c/navi1.gif ><head>にあるものは→  ig/c/s/navi1.gif 画像の保存場所ですが、この設定だと、'ig/c/'が'ig/c/s/'に含まれるので、検索・置換が少し面倒です。プログラムの手間を考えるなら、下記の様に区別しやすい名前の方が良いと思います。 OVERの画像 ig/c/over/navi1.gif OUT の画像 ig/c/out/navi1.gif 上記の場合のサンプル(Winodws環境 IE6,Firefox2で動作確認) <html> <head> <script type="text/javascript"> <!-- //画像の保存場所を変えるときは下記を変更 //ただし包含関係にならない様に注意 var PATH_OVER = 'ig/c/over/'; var PATH_OUT = 'ig/c/out/'; //全てのaタグのをチェック //imgがあり、PATH_OUTの画像であるなら、対象とみなしイベントを登録 window.onload = function(){ var a = document.getElementsByTagName('a'); for(var i = 0;i < a.length;i++){ var img = a[i].getElementsByTagName('img'); if(img){ if(img[0].src.indexOf(PATH_OUT)){ a[i].onmouseover = swapImage; a[i].onmouseout = swapImage; } } } } //PATH_OVERとPATH_OUTを入れ替える function swapImage(){ var img = this.getElementsByTagName('img'); if(img){ if(img[0].src.indexOf(PATH_OVER) >= 0){ img[0].src = img[0].src.replace(PATH_OVER,PATH_OUT); }else if(img[0].src.indexOf(PATH_OUT) >= 0){ img[0].src = img[0].src.replace(PATH_OUT,PATH_OVER); } } } //--> </script> </head> <body> <ul> <li>PATH_OUTの画像なら対象とみなす <li><a href="a.html"><img src="ig/c/out/navi1.gif"></a></li> <li><a href="a.html"><img src="ig/c/out/navi2.gif"></a></li> <li>対象でないAタグは処理しない <li><a href="a.html"><img src="ig1.gif"></a></li> </ul> </body> </html>

etu007
質問者

補足

すごいです! こんなやり方もあるんですね… 試させていただきました。 全く問題なく動きます。 でも、なぜかタスクバー部分にエラーが表示されました。 となります。詳細を見ると エラー’0.src’はNullまたはオブジェクトではありません と表示されます。 これは気にしなくてよいんでしょうか… 問題なく動いてはいるんですけども。

noname#30818
noname#30818
回答No.6

イベントハンドラの完全に外部化 <style type="text/css"> body{white-space:pre;}/*引数を見やすくするためのスタイル*/ </style> <script type="text/javascript"> <!-- window.onload = function(){ var ul = document.getElementById('ABC') var a = ul.getElementsByTagName('a') for(var i = 0;i < a.length;i++){ a[i].onmouseover = over a[i].onmouseout = out } } function out(){ var img = this.getElementsByTagName('img')[0] var url = img.src url = url.split('/') url = '../ig/'+url[url.length-1] //img.src = url document.body.appendChild(document.createTextNode("name Attribute value:" + img.getAttribute('name') + "\tonmouseout:URL=" + url + "\r\n"))//引数の表示(ここでは使わない) MM_swapImgRestore() } function over(){ var img = this.getElementsByTagName('img')[0] var url = img.src url = url.split('/') url = '../ig/'+url[url.length-1].replace(/navi/,'c/navi') img.src = url document.body.appendChild(document.createTextNode("name Attribute value:" + img.getAttribute('name') + "\tonmouseover:URL=" + url + "\r\n"))//引数の表示(確認用) MM_swapImage(img.getAttribute('name'),'',url,1) } //--> </script>

etu007
質問者

補足

すばやい対応ありがとうございます。 もう少しだけ、お助けください。 素直に教えていただいたプログラムを実行すると name Attribute value: onmouseover:URL=../ig/c/navi1.gif name Attribute value: onmouseout:URL=../ig/navi1.gif 上記のようなメッセージが表示されます。 ちなみにファイヤフォックスでは 画像がさし変わって name Attribute value:null onmouseover:URL=../ig/c/navi1.gif name Attribute value:null onmouseout:URL=../ig/navi1.gif が表示されます。 ファイやフォックスのjavascriptコンソールで エラーをチェックすると MM_swapImageとMM_swapImgRestoreが not definedだと表示されます。 エラーがでてしまうのはなぜなんでしょう… 38行目 MM_swapImage(img.getAttribute('name'),'',url,1)と 29行目 MM_swapImgRestore() がおかしい…と指定されてしまいます… どうしてもなぞが解けません… ソースは以下の通りです、おかしな点ありますか? ------------------------------------------------- <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=shift_jis" /> <title>無題ドキュメント</title> <style type="text/css"> body{white-space:pre;}/*引数を見やすくするためのスタイル*/ </style> <script type="text/javascript"> <!-- window.onload = function(){ var ul = document.getElementById('ABC') var a = ul.getElementsByTagName('a') for(var i = 0;i < a.length;i++){ a[i].onmouseover = over a[i].onmouseout = out } } function out(){ var img = this.getElementsByTagName('img')[0] var url = img.src url = url.split('/') url = '../ig/'+url[url.length-1] //img.src = url document.body.appendChild(document.createTextNode("name Attribute value:" + img.getAttribute('name') + "\tonmouseout:URL=" + url + "\r\n"))//引数の表示(ここでは使わない) MM_swapImgRestore() } function over(){ var img = this.getElementsByTagName('img')[0] var url = img.src url = url.split('/') url = '../ig/'+url[url.length-1].replace(/navi/,'c/navi') img.src = url document.body.appendChild(document.createTextNode("name Attribute value:" + img.getAttribute('name') + "\tonmouseover:URL=" + url + "\r\n"))//引数の表示(確認用) MM_swapImage(img.getAttribute('name'),'',url,1) } //--> </script> </head> <body> <ul id="ABC"> <li><a href="a.html"><img src="ig/c/navi1.gif"/></a></li> <li><a href="a.html"><img src="ig/c/navi2.gif"/></a></li> ・ ・ ・ <li></li> </ul> </body> </html>

noname#30818
noname#30818
回答No.5

<html> <head> <meta http-equiv="content-type" content="text/html;charset=shift_jis"> <title>イベントハンドラの完全に外部化</title> <script type="text/javascript"> <!-- window.onload = function(){ var ul = document.getElementById('ABC') var a = ul.getElementsByTagName('a') for(var i = 0;i < a.length;i++){ a[i].onmouseover = over a[i].onmouseout = MM_swapImgRestore } } function over(){ var img = this.getElementsByTagName('img')[0] var url = img.src url = url.split('/') url = '../'+url[url.length-1].replace(/ig/,'ig/c') MM_swapImage(img.getAttribute('name'),"",url,1) } //--> </script> </head> <body> <ul id="ABC"> <li> <a href="a.html"><img src="../ig1.gif" alt="aaa" name="Image1" id="Image1" /></a></li> <li><a href="b.html"><img src="../ig2.gif" alt="bb" name="Image2" id="Image2" /></a></li> ・ ・ ・ </ul> </body> </html> <html> <head> <meta http-equiv="content-type" content="text/html;charset=shift_jis"> <title>nameとidの削除</title> <script type="text/javascript"> <!-- window.onload = function(){ var ev = ["onmouseover","onmouseout"] var ul = document.getElementById('ABC') var a = ul.getElementsByTagName('a') for(var i = 0;i < a.length;i++){ for(var k = 0;k < ev.length:k++){ a[i][ev[k]] = MM_swapImage } } } function MM_swapImage(){ var URL = this.getElementsByTagName('img')[0].src + "" var reg = /\\/ig\\/c/ this.getElementsByTagName('img')[0].src = (URL.match(reg) != null) ? URL.reprace(reg,'/ig') : URL.reprace(/\/ig/,'ig/c') } //--> </script> </head> <body> <ul id="ABC"> <li><a href="a.html"><img src="../ig1.gif"></a></li> <li><a href="a.html"><img src="../ig2.gif"></a></li> </ul> </body> </html>

etu007
質問者

補足

うーん… 数時間格闘しました… どうにも、作動してくれません。特に下のIDやnameを使わないものを 実行したいんですが…(涙) 画像にカーソルをあわせても変化がなく カーソルを離すとエラーですという文字がタスクバー付近にでます…。 原因はわからないんですが… 頭がこんがらがってきました…(涙) それとお手数なんですが… 画像の指定は <body>にあるものは→  ig/c/navi1.gif <head>にあるものは→  ig/c/s/navi1.gif でお考えいただけませんでしょうか… お手数ですが、何卒もう一度ご回答いただけませんでしょうか…

  • venzou
  • ベストアンサー率71% (311/435)
回答No.4

私個人の意見としては、#3さんと同じで、画像ファイル名等に規則性を持たせ、引数を必要としない関数を作るのが良いと思います。 しかし、今から変更するのは大変かもしれませんね。 今のソースをそのまま活用したいなら、匿名関数を利用すれば良いと思います。 サンプル <html> <head> <script language="JavaScript"><!-- function init() { element = document.getElementById("img1"); element.onmouseout = MM_swapImgRestore; element.onmouseover = function (){MM_swapImage('Image1','','../ig/c1.gif',1);}; //↑このように、代入の所で匿名関数を定義します。 //これなら、引数を設定できます。 element = document.getElementById("img2"); element.onmouseout = MM_swapImgRestore; element.onmouseover = function (){MM_swapImage('Image2','','../ig/c2.gif',1);}; } //その他関数定義 // --></script> </head> <body onload="init()"> <ul><li> <a href="a.html" id="img1" > <img src="../ig1.gif" alt="aaa" name="Image1" id="Image1" /> </a> </li> <li> <a href="b.html" id="img2" > <img src="../ig2.gif" alt="bb" name="Image2" id="Image2" /> </a> </li> </ul></body> </html>

etu007
質問者

お礼

う、動きました。ほんとに嬉しいです! ありがとうございます!! でもNO.5さんのidなし分も挑戦してみます!

  • ESate
  • ベストアンサー率64% (11/17)
回答No.3

横槍入れます element = document.getElementById(id); element.onmouseout = MM_swapImgRestore; element.onmouseover = MM_swapImage; // これでは引数を指定できない // element.onmouseover = MM_swapImage("Imagen","","../ig/cn.gif",1)'); // これはMM_swapImageの返り値が代入されるだけ // element.setAttribute('onmouseover', 'MM_swapImage("Imagen","","../ig/cn.gif",1)'); // IEではsetAttributeでイベントハンドラは追加できない MM_swapImageを引数を指定しない、もしくは指定しなくても使えるように改良するのがいいかと思います。 あとどうでもいいことだが、aタグに一つ一つidをつけるのはどうかと思う。 idをつけるならulタグにつけて孫要素としてaタグを参照するか、 aタグにidでなくclassを付与してライブラリなどでよくあるgetElementByClassNameとか使って参照してやるのがいいかと

etu007
質問者

補足

ご意見ありがとうございます いいところまで来ている感じなんですが、 どうにも詰めができません。 おっしゃられるようにMM_swapImageなどと うまく連動していないのかもしれません。 NO.2の方のところにソースを補足しましたので ご意見いただければ助かります

noname#86752
noname#86752
回答No.2

検証してみました。 === a.html === <html> <head> <script type="text/javascript" src="a.js"></script> <script> function init() { e = document.getElementById("link_a"); e.onmouseover = a; e = document.getElementById("link_b"); e.onmouseover = b; } </script> </head> <body onload="init();"> <a href="" id="link_a">aaa</a><br/> <a href="" id="link_b">bbb</a> </body> </html> === a.js === function a() { alert("aaa"); } function b() { alert("bbb"); } これでlink_aではaaaが、link_bではbbbが表示されます。 Firefox2.0.0.3とIE7で試しました。おそらくIE6でも大丈夫でしょう。 もしかしてご要望のものと違っていたらごめんなさい。

etu007
質問者

補足

ありがとうございます。アラートきちんと動きました。 しかし、画像変換がうまくいきません。NO.3の方の指摘にも ありましたが、もしかして MM_swapImgRestoreなどとうまく連動していないのかもしれません。 一応ソースを残しますので、ご意見ください。 function MM_swapImgRestore() { //v3.0 var i,x,a=document.MM_sr; for(i=0;a&&i<a.length&&(x=a[i])&&x.oSrc;i++) x.src=x.oSrc; } function MM_preloadImages() { //v3.0 var d=document; if(d.images){ if(!d.MM_p) d.MM_p=new Array(); var i,j=d.MM_p.length,a=MM_preloadImages.arguments; for(i=0; i<a.length; i++) if (a[i].indexOf("#")!=0){ d.MM_p[j]=new Image; d.MM_p[j++].src=a[i];}} } function MM_findObj(n, d) { //v4.01 var p,i,x; if(!d) d=document; if((p=n.indexOf("?"))>0&&parent.frames.length) { d=parent.frames[n.substring(p+1)].document; n=n.substring(0,p);} if(!(x=d[n])&&d.all) x=d.all[n]; for (i=0;!x&&i<d.forms.length;i++) x=d.forms[i][n]; for(i=0;!x&&d.layers&&i<d.layers.length;i++) x=MM_findObj(n,d.layers[i].document); if(!x && d.getElementById) x=d.getElementById(n); return x; } function MM_swapImage() { //v3.0 var i,j=0,x,a=MM_swapImage.arguments; document.MM_sr=new Array; for(i=0;i<(a.length-2);i+=3) if ((x=MM_findObj(a[i]))!=null){document.MM_sr[j++]=x; if(!x.oSrc) x.oSrc=x.src; x.src=a[i+2];} }

noname#86752
noname#86752
回答No.1

>イベント登録する関数を作って、ページのonloadで実行しておくという感じかな…と考えていたりするんですが… あまり詳しくはないですが、まさに、その方法を取ったことがあります。 例えば・・・ <a href="a.html" id="link_a">......</a> というエレメントのonmounseoutを付けたいなら、 <body onload="init();"> とやっておき(initでなくてもいいですが) headの中のscript内で function init() { var e = document.getElementById("link_a"); e.onmouneover = MM_swapImgRestore; } とやってあげればいく・・・はず。

etu007
質問者

お礼

ありがとうございます! ちょっとトライしてみますね

etu007
質問者

補足

トライさせていただきましたが、 うまく作動しません… 二つ目以降はlink_b、link_c…という風するんですよね? できればonmouseoutやonmouseover両方のプログラムを お教えいただけませんでしょうか。どうぞよろしくお願いします。

関連するQ&A

専門家に質問してみよう