- ベストアンサー
イベントハンドラを完全に外部化にしたい
イベントハンドラをなんとか、完全に外部ファイルにしたいと考えています。 <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はすでに外部化済です
- みんなの回答 (11)
- 専門家の回答
質問者が選んだベストアンサー
- ベストアンサー
細かいことは抜きにして <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> となるわけですね。
その他の回答 (10)
- venzou
- ベストアンサー率71% (311/435)
>エラーの方ですが >ライン:17 >文字:1 エラーが再現できました。 imgタグを含まないaタグがある場合にエラーが出るようです。 配列が空の場合のIF文の条件判断について、ちょっと勘違いしてました、ごめんなさい。 16行目と28行目を修正して下さい。 >if(img){ if(img.length > 0){ これで大丈夫だと思います。
お礼
お手数おかけしました! ありがとうございます!! ほんとに助かりました~!!!!
- venzou
- ベストアンサー率71% (311/435)
>>#他に良回答でてますので、そちらを使って頂いた方が良いかな。 >そうですよね… >すいません ちょっと言葉足らずだったかもしれないので補足しますが、調べるのがめんどくさいからこう書いたわけではなく、他の回答で解決しているなら、こちらの話題は引っ張らない方がよいかな?と思ったので書きました。悪い意味に取らないで下さいね。 エラーに関してはWindowsXP IE6で試しましたがこちらではエラーは出ませんでした。謎ですね。エラーが出てるソースをそのまま使うのは良くないので、とことん追究するか、使わないかのどちらかだと思います。 エラーの原因を追究するなら、 >クリックするとエラー内容が表示されます… この内容を補足願います。(行番号とか出てませんか?) こちらではエラーが再現しないので、解決出来るかわかりませんが、可能な限り調べますよ。 もちろん、こちらのソースを使わないという選択もありですので、判断はお任せします。 ---------------------- ついでに、横槍で回答しますが・・・ >body onload="MM_preloadImages()で これはプレロードの為の物ですので、なくても動きます。 プレロードしておくと、画像の切り替えがスムーズになります。 逆にプレロードしていないと、最初の画像の入れ替え時に、画像を読みにいくので、少し切り替えに時間が掛かるかもしれません。(2回目以降はキャッシュされるので問題ないと思います。) ローカルで開いている場合は、画像を開くのは一瞬なので、違いは分からないと思います。WEB上にアップロードしてから、違いを確認してみてください。(違いを確認する時は、事前にキャッシュをクリアして下さい。) 違いが気にならないようなら、なくても良いと思います。
お礼
ご丁寧にありがとうございます。 venzouさんのは、venzouさんので やり方をマスターしておきたい…という気持ちで おたずねしました。 >body onload="MM_preloadImages()の件は、ありがとうございました エラーの方ですが ライン:17 文字:1 コード:0(ゼロだと思います) となっていました。 でも問題なく作動していました。なぞです。
- venzou
- ベストアンサー率71% (311/435)
>エラー’0.src’はNullまたはオブジェクトではありません #7のプログラムを再度、コピペして確認してみましたが、こちらの環境ではエラーは出ませんでした。 気になるようなら、調べてみますので、ブラウザの種類、エラーが出るタイミング、エラーの場所などもう少し詳しい情報をお願いします。 #他に良回答でてますので、そちらを使って頂いた方が良いかな。
補足
#他に良回答でてますので、そちらを使って頂いた方が良いかな。 そうですよね… すいません 一応どのタイミングかはお伝えしておきます。 ブラウザはIE6です タイミングとしてはサイトを開いた直後。 リロードしても同様です。 エラー表示はページ下のタスクバー部分です。 リンク先が表示されるところです。 そこにページでエラーが発生しました… となります。そこで三角形のびっくりマークを クリックするとエラー内容が表示されます… なぞです。 あまり労力が必要であれば、締切させていただきますので。 特に問題なし、とでもご記載いただけますか。 よろしくお願いします。
- venzou
- ベストアンサー率71% (311/435)
><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>
補足
すごいです! こんなやり方もあるんですね… 試させていただきました。 全く問題なく動きます。 でも、なぜかタスクバー部分にエラーが表示されました。 となります。詳細を見ると エラー’0.src’はNullまたはオブジェクトではありません と表示されます。 これは気にしなくてよいんでしょうか… 問題なく動いてはいるんですけども。
イベントハンドラの完全に外部化 <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>
補足
すばやい対応ありがとうございます。 もう少しだけ、お助けください。 素直に教えていただいたプログラムを実行すると 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>
<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>
補足
うーん… 数時間格闘しました… どうにも、作動してくれません。特に下のIDやnameを使わないものを 実行したいんですが…(涙) 画像にカーソルをあわせても変化がなく カーソルを離すとエラーですという文字がタスクバー付近にでます…。 原因はわからないんですが… 頭がこんがらがってきました…(涙) それとお手数なんですが… 画像の指定は <body>にあるものは→ ig/c/navi1.gif <head>にあるものは→ ig/c/s/navi1.gif でお考えいただけませんでしょうか… お手数ですが、何卒もう一度ご回答いただけませんでしょうか…
- venzou
- ベストアンサー率71% (311/435)
私個人の意見としては、#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>
お礼
う、動きました。ほんとに嬉しいです! ありがとうございます!! でもNO.5さんのidなし分も挑戦してみます!
- ESate
- ベストアンサー率64% (11/17)
横槍入れます 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とか使って参照してやるのがいいかと
補足
ご意見ありがとうございます いいところまで来ている感じなんですが、 どうにも詰めができません。 おっしゃられるようにMM_swapImageなどと うまく連動していないのかもしれません。 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でも大丈夫でしょう。 もしかしてご要望のものと違っていたらごめんなさい。
補足
ありがとうございます。アラートきちんと動きました。 しかし、画像変換がうまくいきません。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];} }
>イベント登録する関数を作って、ページの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; } とやってあげればいく・・・はず。
お礼
ありがとうございます! ちょっとトライしてみますね
補足
トライさせていただきましたが、 うまく作動しません… 二つ目以降はlink_b、link_c…という風するんですよね? できればonmouseoutやonmouseover両方のプログラムを お教えいただけませんでしょうか。どうぞよろしくお願いします。
お礼
ありがとうございます!!! 無事に動かせました。とてもとても…助かりました。 蛇足ですが、今まで ig/c/s/navi1.gif~などは body onload="MM_preloadImages()で 読み込んでいたんですが、これはもうなくても 問題ないでしょうか? やっている限り問題なさそうなのですが… しばらくお待ちしてコメントいただけなければ 締めさせていただきます。 ありがとうございました。 ※MM_preloadImagesの内容については NO2さんへの補足をご覧ください。