- ベストアンサー
【JavaScript】event量産方法とエラー対策について
- JavaScriptを使用して、複数の<a>タグをループさせて同じURLにジャンプさせる方法について教えてください。
- また、ループの回数を変更した場合にエラーが発生しないようにするための対策も教えてください。
- その他、センセーショナルな部分についても教えていただけると助かります。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
いわゆるクロージャで引数束縛する方法もありますが、そもそも論として、いちいちループでイベントハンドラを取り付ける書き方をしないで下さい。多くの場合、有害です。 click はバブリングしますし、この場合は ID が振られていますので、祖先ノードで監視すれば十分です。 addevent(document, 'click', function (e) { var t = e.target || e.srcElement; var c; CHECK: { for (var c = t; c; c = c.parentNode) if (c.id && c.id.indexOf('page') == 0) break CHECK; return false; } // c は id="page*" を持つ要素 });
その他の回答 (3)
- Chaire
- ベストアンサー率60% (79/130)
詳細は他の方々のリンク先を見て頂くとして、ごく簡単に説明します。下の例で「ほげ」をクリックしたとき、どのイベントハンドラが実行されるでしょうか? <body onclick="alert('BODY')"> <div onclick="alert('DIV')"> <p onclick="alert('P')">ほげ</p> </div> </body> 試せばすぐ分かりますが、正解は "P" → "DIV" → "BODY" の順に全て実行される、です。これをバブリングと呼びますが、小難しい用語はともかく、「p のクリック」は親である「div のクリック」でもあり、さらに「body で生じたクリック」でもあるのを考えれば、当たり前の動作と言えるでしょう。 と言うことは、一番上の body で click を監視すれば、その下で生じるクリックを全て感知できることが分かります。最初にどこがクリックされたか(上の場合は p)は、event オブジェクトの event.target(IE8 以下では event.srcElement)に記録されています。event.target から parentNode を辿っていけば、そのままバブリングの経路になります。 通常、event オブジェクトはイベントハンドラの第一引数に渡されています。HTML のイベント属性の中では "event" という名前のオブジェクトを使えます。 以上より。 <ul onclick=" // クリックの発生源 var t = event.target || event.srcElement; var c; CHECK: { // 発生源自身、あるいは祖先が li[@id="page.."] であれば、 // li[@id="page.."] がクリックされたと見なせる。 // 見慣れない処理かもしれないが、 // 実は CSS のセレクタマッチングの手順と同じ。 for (c = t; c; c = c.parentNode) { if (c.tagName == 'li' && c.id && c.id.indexOf('page') == 0) { // クリックされた li[@id="page.."] が見つかった。 // ループを抜ける。 break CHECK; } } // クリックされた li[@id="page.."] がない。 // つまり、li と li の間など別の場所がクリックされただけ。 // 終了する。 return false; } // この時点で、c はクリックされた li[@id="page.."]。 // 処理を続行。 // .... "> <li id="p_prev"><a href="pre">PREV</a></li> <li id="page1"><a href="p1">1</a></li> <li id="page2"><a href="p2">2</a></li> <li id="p_next"><a href="nex">NEXT</a></li> </ul> --- DOM 文書木は頻繁に変更されます。例えば、innerHTML でごっそりと中身を書き換える人がたくさんいますが、そうするとイベントハンドラも根こそぎ消されます。新しく書き換えられた中身に再び同じイベントハンドラを取り付けてくれるなど、誰が期待できるでしょうか? 面倒を避けるには、危険地帯から遠くで監視した方が良い。上では ul で監視していますが、もっと安全性を重視するなら body より上で監視すれば良い。すると必然的にイベント情報を event に問い合わせるようになります。 document.addEventListener('click', function (event) {...}, false); また、こうすれば『ページ内に存在しない id を指定しても……エラーに』なるかなどと心配することもありません。クリックされた時点で文書内に存在する id だけを対象にするからです。であれば、load を待つ必要すらありません。どの読み込み段階であれ、ブラウザ上なら最初から document があるのですから。
お礼
回答ありがとうございます! ちょうどお礼を書いてたところで、戻ってきてレレレでしたw 『load を待つ必要すらありません。』 これ気になるので、もっと掘り下げようかと思っています。 実は複数の他の言語(イベントのないようなあるような言語)をやっていたので、ちょっと混乱していましたが、おかげでちょっと深みが見れたような気がします。
- think49
- ベストアンサー率59% (285/482)
補足のHTMLに関しては CSS の #p_set a { display: block; } だけで解決できそうなんですが、JavaScript を使わないとダメでしょうか? バブリングに関しては「イベントバブリング」や「イベントバブル」でGoogle検索すると関連情報が HIT します。 ■平易な解説 イベントバブル - DOM-Level-2 http://vird2002.s8.xrea.com/javascript/DOM-Level-2_Event_bubbling.html 掲示板/JavaScript質問板/過去ログ/一覧/ 右クリで呼び出しができるならば、ボタン3では? - TAG index Webサイト http://www.tagindex.com/kakolog/q4bbs/1601/1871.html JavaScript初級者から中級者になろう:三章第三回 イベントバブリング http://uhyohyohyo.sakura.ne.jp/javascript/3_3.html ■詳しい解説 1.2.3 イベントバブル動作 - DOM Level 2 Events http://www.y-adagio.com/public/standards/tr_dom2_events/events.html#Events-flow-bubbling-h3 XML Events入門 http://www.ibm.com/developerworks/jp/xml/library/x-events/ XML Events http://www2u.biglobe.ne.jp/~oz-07ams/prog/xml-events/Overview-ja.html イベントモデルの概念と用語法が混乱しているので、イライライするんですが - 檜山正幸のキマイラ飼育記 http://d.hatena.ne.jp/m-hiyama/20071205/1196838087
お礼
回答ありがとうございます! 補足のHTMLはシンプルにしたもので、デザイン上実はかなり複雑なことになっていまして(大きな箱の中に文字が少しなのであいてる部分も同じリンクにしたかったのです)、当初onClickで実装しようかと思っていたところ、XHTML Validationに怒られてw それでイベントでやってみようかということでした。 ご紹介いただいたリンク参考になりました。 実はこういうちゃんとした解説ページ探してたのですが、どうやらギリギリ理解して解説しているページばかり見ていたようです。
- fujillin
- ベストアンサー率61% (1594/2576)
横から失礼。 ご提示の例だと、単にリンクを設定しているだけのように見えますが… #1の補足をみると、おまけにリンクタグを用いているようですが、そもそもリンクタグの機能がクリックした時にリンクをさせるためのもののはず。 トップへのリンクを指定したいのであれば、targetを指定しておくことで可能なではないでしょうか。 あるいはbase targetを指定しておいてもよいのかも。(←DOCTYPEにもよりますが…) そのほうが、スクリプトオフの環境でも確実に実行されることを期待できます。 それはおいておいて、ご提示の例の場合、 addevent($(names), "click", function(){ lh(names); }); で、後半の変数namesの内容は、上記のステートメントが実行されるときではなく、function(){ lh(names); }が実行されるとき(=クリックイベント発生時)に評価されます。 addevent実行時にはnamesは意図した内容を保持していますが、function実行時には値が変わってしまっています。(ループで変えているので) そのあたりが、思うように動かない原因かと。 意図したような処理を実現するには、#1様が触れているように、namesの内容が変わっても定義したときの値が保持されるような仕組みを考える必要があります。 例えば、上記の部分を addevent($(names), "click", setName(names)); とでもしておいて function setName(name){ return function(){ lh(name); }; } を定義しておくようなことをしてあげれば、設定するときのnamesの内容が保持されるので、意図したような動作になるかと思います。 関数(setName)を作らずに匿名関数で処理する方法もありますのでお調べください。 とはいうものの、#1様がご指摘のように、 『事前に全ての必要要素にそれぞれイベントをセットしておく』というこの方法は、ほとんど同じ処理を数多くセットするという意味で効率的とは言えません。(他にも推奨しない理由はいろいろありますが) #1で例示されているように、『イベントが発生した要素の親要素にpage#というidを持つものがあればリンク処理を行なう』という処理にしてイベント処理を一つだけ、上流側(ここではdocument)にセットしておくのが効率的です。 >適当回数ループしないで親ノードから"page"を含む子ノードを探して >ということなんだろうな・・・ くらいのところまでです どうも理解なさっていないように思われます。 >(ただ動けばいいというふうには思っていなく理解したいがためです) たいへん正しい姿勢と思いますので、まずは#1の回答の内容、次にクロージャの仕組みの順で理解する方が分かりやすいかと思います。 イベントのバブリングについてあたりが参考になるかも知れません。 http://vird2002.s8.xrea.com/javascript/DOM-Level-2_Event_bubbling.html http://d.hatena.ne.jp/snaka72/20100925/1285404467 http://d.hatena.ne.jp/monjudoh/20080407/1207592217
お礼
回答ありがとうございます! イベントのバブリング 初めて理解しました。 #1さんの解説という意味ではなにをさがせがいいのかわかりとても参考になりました。 ご紹介いただいたリンクで、わたしなりに理解できました。 どちらをベストアンサーにしようかすごく迷っているところです。
お礼
回答ありがとうございます! 最初見たときには、なにがなんだかだったのですが、後の方の回答を読むとなるほどということがわかりました。 addevent( window,"load", function(){ addevent(document, 'click', function (event) { var target = event.target || event.srcElement; var current; CHECK: { for (var current = target; current; current = current.parentNode) { if (current.id && (current.id.indexOf('page') == 0 || current.id.match('_link'))) { lh(current.id); //alert(current.id); break CHECK; return false; } } } }); } ); 最終的にはこれで落ち着きそうです。 前後しましたが、いろいろ学習した今見てみると とても的確な回答だということがわかりベストアンサーとさせていただきます。
補足
早速の回答ありがとうございます。 徹夜してたので寝てしまって遅くなりました。 ん~よくわかりません(ごめんなさい) 適当回数ループしないで親ノードから"page"を含む子ノードを探して ということなんだろうな・・・ くらいのところまでです。 とりあえず書き忘れていたHTML部分は <ul id="p_set"> <li id="p_prev"><a href="pre">PREV</a></li> <li id="page1"><a href="p1">1</a></li> <li id="page2"><a href="p2">2</a></li> <li id="page3"><a href="p3">3</a></li> <li id="page4"><a href="p4">4</a></li> <li id="p_next"><a href="nex">NEXT</a></li> </ul> シンプルにするとこんな感じです。 それと、スクリプトは上記したのみです。 できれば引き続き噛み砕いたところをお願いします。 (ただ動けばいいというふうには思っていなく理解したいがためです)