diff options
author | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
---|---|---|
committer | Peter Bengtsson <mail@peterbe.com> | 2020-12-08 14:40:17 -0500 |
commit | 33058f2b292b3a581333bdfb21b8f671898c5060 (patch) | |
tree | 51c3e392513ec574331b2d3f85c394445ea803c6 /files/ja/learn/javascript/building_blocks/events/index.html | |
parent | 8b66d724f7caf0157093fb09cfec8fbd0c6ad50a (diff) | |
download | translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.gz translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.bz2 translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.zip |
initial commit
Diffstat (limited to 'files/ja/learn/javascript/building_blocks/events/index.html')
-rw-r--r-- | files/ja/learn/javascript/building_blocks/events/index.html | 597 |
1 files changed, 597 insertions, 0 deletions
diff --git a/files/ja/learn/javascript/building_blocks/events/index.html b/files/ja/learn/javascript/building_blocks/events/index.html new file mode 100644 index 0000000000..7c40419c10 --- /dev/null +++ b/files/ja/learn/javascript/building_blocks/events/index.html @@ -0,0 +1,597 @@ +--- +title: イベントへの入門 +slug: Learn/JavaScript/Building_blocks/Events +tags: + - Beginner + - CodingScripting + - JavaScript + - イベント + - イベントハンドラー + - ガイド + - 学習 + - 記事 +translation_of: Learn/JavaScript/Building_blocks/Events +--- +<div>{{LearnSidebar}}</div> + +<div>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Return_values","Learn/JavaScript/Building_blocks/Image_gallery", "Learn/JavaScript/Building_blocks")}}</div> + +<p class="summary">イベントは、あなたがプログラムを書いているシステムで生じた動作、出来事を指します。システムからあなたへ、イベントとして何かあった事を知らせてくるので、必要であればそれに何らかの反応を返す事ができます。例えば、ユーザーがウェブページ上でボタンを押したとき、ある情報を表示するように反応させたいと思うかもしれません。この記事では、イベントに関する重要な概念を取り上げ、ブラウザーの中でのイベントの振る舞いを見ていきます。ここでは、全てを説明するのではなく、この段階で知っておくべき内容を取り上げます。</p> + +<table class="learn-box standard-table"> + <tbody> + <tr> + <th scope="row">前提条件:</th> + <td>コンピューターに関する基本的な知識があること。HTML と CSS について理解していて、<a href="/ja/docs/Learn/JavaScript/First_steps">JavaScript の第一歩</a>の記事を理解していること。</td> + </tr> + <tr> + <th scope="row">目的:</th> + <td>イベントの基本的な理論を理解すること。ブラウザーでの振る舞いを理解し、プログラミング環境が変わると、イベントの振る舞いが変わることを理解すること。</td> + </tr> + </tbody> +</table> + +<h2 id="A_series_of_fortunate_events" name="A_series_of_fortunate_events">運命的なイベントの連続</h2> + +<p>先ほど説明しましたが、<strong>イベント</strong>はあなたがプログラムしているシステムの中で生じた動作や出来事です。つまり、あるイベントが起きたときに、システムはある種の信号を発します。さらに、ある種のアクションが自動的に実行されるためのメカニズムも提供します。例えば、空港では、飛行機が離陸するために滑走路がクリアになった時に、信号がパイロットに送られます。その結果、パイロットは飛行機の操縦を開始します。</p> + +<p><img alt="" src="https://mdn.mozillademos.org/files/14077/MDN-mozilla-events-runway.png" style="display: block; margin: 0px auto;"></p> + +<p>ウェブの場合は、イベントは、ブラウザーのウィンドウの中で発火されます、そしてその中に属する特定の項目に紐付く傾向にあります — これは単一の要素、要素の集合、現在のタブでロードされた HTML 文書、ブラウザー画面全体といったものです。発生するイベントはたくさんの異なる種類があります。例をあげると。</p> + +<ul> + <li>ユーザーがある要素の上をマウスでクリックしたり、ある要素の上にカーソルを持ってくる</li> + <li>ユーザーがキーボードのキーを押す</li> + <li>ユーザーがブラウザー画面をリサイズしたり閉じたりする</li> + <li>ウェブページのロードの完了</li> + <li>フォームの送信</li> + <li>ビデオが再生中、停止中、再生が終わった</li> + <li>エラーの発生</li> +</ul> + +<p>ここや MDN <a href="/ja/docs/Web/Events">Event リファレンス</a>を覗いてみれば、<strong>とてもたくさん</strong>の応答可能なイベントがあるのが判るでしょう。</p> + +<p>それぞれの利用可能なイベントには<strong>イベントハンドラー</strong>があり、これはイベントに発火した時に実行される (通常はユーザー定義の JavaScript 関数) コードのブロックのことです。イベントの発火に対する応答としてコードのブロックが実行されるように定義する事を、<strong>イベントハンドラーを登録する</strong>と言います。イベントハンドラーは時に<strong>イベントリスナー</strong> と呼ばれる事を付記しておきます—我々の目的から見ると言い変えてもほとんど問題ないのですが、厳密に言えば一緒に動作する別のものです。イベントリスナーはイベントの発生を監視し、イベントハンドラーは発生したイベントの応答として動作するコードです。</p> + +<div class="note"> +<p><strong>メモ</strong>: 大事な事ですがウェブのイベントは JavaScript 言語の主要部分の一部ではありません — ブラウザーに組み込まれた JavaScript API の一部として定義されたものです。</p> +</div> + +<h3 id="A_simple_example" name="A_simple_example">簡単な例</h3> + +<p>ここで何を言ってるのか説明するため、簡単な例を見てみましょう。このコースでこれまでに例の多くに使われているイベントやイベントハンドラーを見てきました、しかし、知識を固めるために整理をしましょう。続く例では、押すと背景色がランダムに変化する {{htmlelement("button")}} が一つあります:</p> + +<pre class="brush: html notranslate"><button>Change color</button></pre> + +<div class="hidden"> +<pre class="brush: css notranslate">button { margin: 10px };</pre> +</div> + +<p>JavaScript はこのようになります:</p> + +<pre class="brush: js notranslate">const btn = document.querySelector('button'); + +function random(number) { + return Math.floor(Math.random() * (number+1)); +} + +btn.onclick = function() { + const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +}</pre> + +<p>このコードでは、<code>btn</code> という変数に {{domxref("Document.querySelector()")}} 関数を使って取得したボタンへの参照を格納しています。それとは別にランダムな数値を返す関数も定義しています。コードの 3 つ目の部分はイベントハンドラーです。<code>btn</code> 変数は<code><a href="https://wiki.developer.mozilla.org/ja/docs/Web/HTML/Element/button"><button></a></code>要素を指していますが、この種のオブジェクトにはたくさん発火し得るイベントがあるので、色々なイベントハンドラーが使えます。<code><a href="https://wiki.developer.mozilla.org/ja/docs/Web/API/GlobalEventHandlers/onclick">onclick</a></code> イベントハンドラプロパティに、ランダムな RGB色を生成し <code><a href="https://wiki.developer.mozilla.org/ja/docs/Web/HTML/Element/body"><body></a></code> の <code><a href="https://wiki.developer.mozilla.org/ja/docs/Web/CSS/background-color">background-color</a></code> を設定するコードを抱えた匿名関数を代入する事で、<code><a href="https://wiki.developer.mozilla.org/ja/docs/Web/API/Element/click_event">click</a></code> イベントが発火されるのを待ちかまえます。</p> + +<p>このコードは <code><button></code> 要素でクリックイベントが発火すれば常に実行されます、要はユーザーがクリックしたらいつでも。</p> + +<p>この例の出力は以下のようになります:</p> + +<p>{{ EmbedLiveSample('A_simple_example', '100%', 200, "", "", "hide-codepen-jsfiddle") }}</p> + +<h3 id="Its_not_just_web_pages" name="It's_not_just_web_pages">ただのウェブページではありません</h3> + +<p>ここで言及しておくべき事は、イベントは JavaScript 固有のものではないという事です — ほとんどのプログラミング言語はいくつかのイベントモデルを持ち、その動作する方法はしばしは JavaScript の方式とは異なっています。実際、ウェブページの JavaScript のイベントモデルは他の環境で用いられている JavaScript のイベントモデルと異なっています。</p> + +<p>例えば、<a href="/ja/docs/Learn/Server-side/Express_Nodejs">Node.js</a> は開発者に JavaScript でネットワークとサーバーサイドのアプリケーションを構築することを可能にするとても有名な JavaScript ランタイムです。<a href="https://nodejs.org/docs/latest-v12.x/api/events.html">Node.js event model</a> はイベントを待ち受けるリスナー、イベントを定期的に発生させるエミッターに依拠しています —たいして違ってないように聞こえますが、コードは極めて異なっていて、イベントリスナーを登録する <code>on()</code> や、一度実行したら登録を解除するイベントリスナーを登録するための <code>once() </code> のような関数を使っていきます。<a href="https://nodejs.org/docs/latest-v12.x/api/http.html#http_event_connect">HTTP connect event docs</a> が使い方の良い例を教えてくれます。</p> + +<p>その他の例として、<a href="/ja/docs/Mozilla/Add-ons/WebExtensions">WebExtensions</a> と呼ばれる技術を使って、クロスブラウザーアドオン (ブラウザーの機能拡張) を JavaScript で作成できます。イベントモデルは Web イベントモデルと似ていますが、ほんの少し違いがあります (イベントリスナーのプロパティはキャメルケース (例 <code>onmessage</code> でなく <code>onMessage</code>) で命名されていて、<code>addListener</code> 関数で結び付ける必要があります。例として <a href="/ja/Add-ons/WebExtensions/API/runtime/onMessage#Examples"><code>runtime.onMessage</code> page</a> を確認してください。</p> + +<p>学習の今の段階で、そのような他の環境について何か理解する必要はありません。イベントは異なるプログラミング環境では異なることがあるとだけ認識してください。</p> + +<h2 id="Ways_of_using_web_events" name="Ways_of_using_web_events">ウェブイベントの使用方法</h2> + +<p>関連づけたいイベントが発火した時に走らせたいイベントリスナーコードを ウェブページに追加する方法はいろいろあります。このセクションでは様々なメカニズムを見ていき、どれを使うべきなのか議論していきます。</p> + +<h3 id="Event_handler_properties" name="Event_handler_properties">イベントハンドラープロパティ</h3> + +<p>イベントハンドラーコードを代入するためのいろいろなプロパティがあり、そういったものをここまでのコースで最もたくさん見てきました。上記の例に戻りましょう。</p> + +<pre class="brush: js notranslate">const btn = document.querySelector('button'); + +btn.onclick = function() { + const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +}</pre> + +<p><code><a href="/ja/docs/Web/API/GlobalEventHandlers/onclick">onclick</a></code> プロパティがこの例で使用されているイベントハンドラープロパティです。ボタンで利用可能なプロパティ(例えば <code><a href="/ja/docs/Web/API/Node/textContent">btn.textContent</a></code> や <code><a href="/ja/docs/Web/API/HTMLElement/style">btn.style</a></code>)のうちの 1 プロパティに過ぎませんが、特別な種類のものです(コードを代入すると、そのコードはボタンでイベントが発火した際に実行される)。</p> + +<p>ハンドラープロパティには、名前付き関数の関数名 (<a href="/ja/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">Build your own function</a> でみられるような) を設定することもできます。こう書いても動作は同じです:</p> + +<pre class="brush: js notranslate">const btn = document.querySelector('button'); + +function bgChange() { + const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +} + +btn.onclick = bgChange;</pre> + +<p>利用できるイベントハンドラープロパティにはとてもたくさんの種類があります。実験してみましょう。</p> + +<p>まずは、<a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/random-color-eventhandlerproperty.html">random-color-eventhandlerproperty.html</a> のローカルコピーを作成し、ブラウザーで開いてくださいこれはこの記事ですでに遊んだ簡単なランダム色のサンプルです。さて、<code>btn.onclick</code> のところを以下の異なる値に変えてみて、結果を順に見てみてください:</p> + +<ul> + <li><code><a href="/ja/docs/Web/API/GlobalEventHandlers/onfocus">btn.onfocus</a></code> と <code><a href="/ja/docs/Web/API/GlobalEventHandlers/onblur">btn.onblur</a></code> — ボタンがフォーカスされフォーカスが外れる(Tab キーをパチパチして、ボタンをフォーカスしたり外したりしてみて)と色が変わります。これらはフォームのフィールドがフォーカスされている時にフィールドに何を入れたらいいのか示したり、フィールドの入力が終った直後に入力として正しくない値が入っている際のエラーメッセージを表示するような場合によく使われます。</li> + <li><code><a href="/ja/docs/Web/API/GlobalEventHandlers/ondblclick">btn.ondblclick</a></code> — ダブルクリックされた場合だけ色が変わります。</li> + <li><code><a href="/ja/docs/Web/API/GlobalEventHandlers/onkeypress">window.onkeypress</a></code>, <code><a href="/ja/docs/Web/API/GlobalEventHandlers/onkeydown">window.onkeydown</a></code>, <code><a href="/ja/docs/Web/API/GlobalEventHandlers/onkeyup">window.onkeyup</a></code> — キーボードのキーが押された時に色が変わります。<code>keypress</code> は普通のキー入力(ボタンを押して離して)を示しますが、<code>keydown</code> と <code>keyup</code> はキーストロークのうち押すだけ、離すだけの部分それぞれを指します。ボタンそのもののイベントハンドラーに登録しても上手く動かないことに注意してください — <a href="/ja/docs/Web/API/Window">window</a> オブジェクトに登録しなければならず、これはブラウザーのウィンドウ全体を表わしています。</li> + <li><code><a href="/ja/docs/Web/API/GlobalEventHandlers/onmouseover">btn.onmouseover</a></code> と <code><a href="/ja/docs/Web/API/GlobalEventHandlers/onmouseout">btn.onmouseout</a></code> — マウスポインタがボタンの上に来たときとボタンの上から外れた時に色が変わります。</li> +</ul> + +<p>いくつかのイベントはとても汎用的なのでほとんどどこでも使えます(例えば onlick ハンドラはほぼ全ての要素に登録できます)が、いくつかはもっと限定的で、特定の状況でしか使えません(例えば <a href="https://developer.mozilla.org/ja/docs/Web/API/GlobalEventHandlers/GlobalEventHandlers.onplay">onplay </a> は{{htmlelement("video")}}のような特定の要素でのみ意味を持ちます)。</p> + +<h3 id="インラインイベントハンドラー_—_使っちゃだめ">インラインイベントハンドラー — 使っちゃだめ</h3> + +<p>あなたのコードでこんな形を見た事があるかもしれません:</p> + +<pre class="brush: html notranslate"><button onclick="bgChange()">Press me</button> +</pre> + +<pre class="brush: js notranslate">function bgChange() { + const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +}</pre> + +<div class="note"> +<p>メモ: <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/random-color-eventhandlerattributes.html">こちら</a>に GitHub上のサンプルがあります (また、<a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/random-color-eventhandlerattributes.html">こちら</a>で実際に動くところを見られます)。</p> +</div> + +<p>Web 上で見かける最初期のイベントハンドラー登録方法には、上の例のような<strong>イベントハンドラーHTML属性</strong>(<strong>インラインイベントハンドラー</strong>とも言う)があります — 属性値がイベント発生時に実行したい JavaScript コードそのものです。上の例では{{htmlelement("script")}}要素の中で定義された関数を起動していますが、直接JavsScript そのものを属性の中に入れる事もできます。例えば:</p> + +<pre class="brush: html notranslate"><button onclick="alert('Hello, this is my old-fashioned event handler!');">Press me</button></pre> + +<p>多くのイベントハンドラープロパティと等価な HTML属性を見付けるでしょうが、使うべきではありません — こういうのは悪い方法とみなされています。ちょっとした事を手早く片づけたい時、イベントハンドラー属性を使うのが簡単に思えるかもしれませんが、あっという間に手がつけられない、効率の悪いものになってしまいます。</p> + +<p>そもそも、あなたの HTML と JavaScript を混在させると、読みにくくなってしまうため、良いアイデアではありません — あなたの JavaScript は一ヶ所にまとめる方が良いです。別の一つのファイルになっていれば、それを複数の HTML ドキュメントに適用できますから。</p> + +<p>(HTML と JavaScript が)一つのファイルになっているとしても、インラインイベントハンドラーは良いアイデアではありません。ボタン一つならいいですが、ボタンが 100 あったら? ファイルに 100 の属性を追加したならば、あっという間に管理していくのは悪夢と化す事でしょう。JavaScript を使えば、ページにボタンがいくつあろうが、全部のボタンにイベントハンドラーを追加するのは簡単です、こんな具合です:</p> + +<pre class="brush: js notranslate">const buttons = document.querySelectorAll('button'); + +for (let i = 0; i < buttons.length; i++) { + buttons[i].onclick = bgChange; +}</pre> + +<p class="brush: js">ここにある他のオプションは <code><a href="https://wiki.developer.mozilla.org/ja/docs/Web/API/NodeList">NodeList</a></code> オブジェクトの組み込みメソッドの <code><a href="https://wiki.developer.mozilla.org/ja/docs/Web/API/NodeList/forEach">forEach()</a></code> で使えることに注意してください:</p> + +<pre class="brush: js notranslate">buttons.forEach(function(button) { + button.onclick = bgChange; +});</pre> + +<div class="note"> +<p><strong>注</strong>: プログラムロジックをコンテンツから分離しておくと、あなたのサイトはサーチエンジンにとってより好ましいものになります。</p> +</div> + +<h3 id="addEventListener_と_removeEventListener">addEventListener() と removeEventListener()</h3> + +<p>最新のイベント機構は <a href="https://www.w3.org/TR/DOM-Level-2-Events/">Document Object Model (DOM) Level 2 Events</a> 仕様で規定されていて、ブラウザーに新しい関数が追加されました — <code><a href="/ja/docs/Web/API/EventTarget/addEventListener">addEventListener()</a></code>です。この関数はイベントハンドラープロパティと同じ方向性ですが、文法は明確に異なります。ランダム色の例をこんな風に書き換える事ができます:</p> + +<pre class="brush: js notranslate">const btn = document.querySelector('button'); + +function bgChange() { + const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +} + +btn.addEventListener('click', bgChange);</pre> + +<div class="note"> +<p>メモ: <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/random-color-addeventlistener.html">こちら</a>に GitHub上のサンプルがあります (また、<a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/random-color-addeventlistener.html">こちら</a>で実際に動くところが見られます)。</p> +</div> + +<p><code>addEventListener()</code> 関数のカッコの中で、二つの引数を指定しています — ハンドラーを登録したいイベントの名前と、それに反応して実行させたいコードを含んだ関数です。匿名関数を使って、実行したいコードを全部 addEventListener() 関数の引数に書いてしまっても全く問題ありません。こんな具合です:</p> + +<pre class="brush: js notranslate">btn.addEventListener('click', function() { + const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + document.body.style.backgroundColor = rndCol; +});</pre> + +<p>この方式は、ここまでで見てきた古い方式に勝る点がいくつかあります。まず第一に、逆を行なう関数 <code><a href="/ja/docs/Web/API/EventTarget/removeEventListener">removeEventListener()</a></code>があり、以前に追加したリスナーを削除できます。例えばこうすると、このセクションの最初のコード部で追加したリスナーを削除します:</p> + +<pre class="brush: js notranslate">btn.removeEventListener('click', bgChange);</pre> + +<p>単純で小さなプログラムではたいした事ありませんが、大きくて複雑なプログラムでは、古く使われないイベントハンドラーを除去しておくと効率が良くなります。さらに、これは例えば同じボタンに状況の違いによって異なる動作をさせる事ができるようになります — ただ適切なイベントハンドラーを追加したり削除するだけで良いのです。</p> + +<p>第二に、同じリスナーに複数のハンドラーを登録できます。<br> + 次では二つのハンドラの両方は適用されません:</p> + +<pre class="brush: js notranslate">myElement.onclick = functionA; +myElement.onclick = functionB;</pre> + +<p>二行目で最初に設定した <code>onclick</code> の値が上書きされるからです。<br> + ですがこれなら動きます:</p> + +<pre class="brush: js notranslate">myElement.addEventListener('click', functionA); +myElement.addEventListener('click', functionB);</pre> + +<p>要素がクリックされると、どちらの関数も走ります。</p> + +<p>さらには、この方式ではもっとたくさんのパワフルな機能やオプションが使えます。それらはこの記事の範疇を少しばかり超えているので、知りたければ <code><a href="/ja/docs/Web/API/EventTarget/addEventListener">addEventListener()</a></code> と <code><a href="/ja/docs/Web/API/EventTarget/removeEventListener">removeEventListener()</a></code> のリファレンスページを見てください</p> + +<h3 id="What_mechanism_should_I_use" name="What_mechanism_should_I_use">どの方式を使えば良い?</h3> + +<p>三つの方式のうち、イベントハンドラーHTML属性は絶対使うべきではありません — 前に書いたように、時代遅れで悪いやり方です。</p> + +<p>他の二つはまあまあどっちでも良いです、少なくとも単純な用途では:</p> + +<ul> + <li>イベントハンドラープロパティは力とオプションに欠けますが、ブラウザー間での互換性が高いです(IE8 ですら動きます)。学習を始めるならここから始めるのが良いかもしれません。</li> + <li>DOM レベル 2 イベント(<code>addEventListener()</code>他)はもっとパワフルですが、もっと複雑でちょっと互換性に欠けます(IE9以降でサポート)。こちらも試していき、可能なところではこちらを使えるようになりましょう。</li> +</ul> + +<p>三番目の方式の最大の利点は、必要なときに removeEventListener() 関数でイベントハンドラーコードを削除できる事、必要なときは要素に同種のリスナーを複数追加できる事です。例えば、ある要素に対して <code>addEventListener('click', function() { ... })</code> を別の関数を第二引数に指定して何回か呼ぶ事ができます。これはイベントハンドラープロパティでは、プロパティは後からセットした値で上書きされてしまうので、できません。e.g.:</p> + +<pre class="brush: js notranslate">element.onclick = function1; +element.onclick = function2; +etc.</pre> + +<div class="note"> +<p><strong>注</strong>: もし仕事で IE8 より古いブラウザーをサポートするよう言われているなら、そのような古代のブラウザーは新しいものとは違ったイベントモデルを使っているため、困難にぶつかるかもしれません。でも怖がらないで。大半の JavaScript ライブラリ(例えば <code>jQuery</code>)には、ブラウザー間の差異をとっぱらえる関数が備わっています。勉強中のあなたがこの点について心配しすぎる必要はありません。</p> +</div> + +<h2 id="Other_event_concepts" name="Other_event_concepts">その他、イベントに関する概念</h2> + +<p>このセクションでは、イベントに関連するより進んだ概念について軽くさらっていきます。今の時点で完全に理解する必要があるほど重要ではありませんが、ときどき見かけることになるであろうコードのパターンがなぜそうなっているのか、理解する助けになるかもしれません。</p> + +<h3 id="Event_objects" name="Event_objects">Event objects</h3> + +<p>ときどきイベントハンドラー関数内で <code>event</code>、evt、単に <code>e</code> などと名付けられた引数を見かけるかもしれません。<br> + これらは<strong>イベントオブジェクト</strong>と呼ばれ、イベントの追加機能や情報を提供する目的でイベントハンドラーに自動的に渡されます。例えば、またランダム色の例をちょっと書き換えてみましょう:</p> + +<pre class="brush: js notranslate">function bgChange(e) { + const rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + e.target.style.backgroundColor = rndCol; + console.log(e); +} + +btn.addEventListener('click', bgChange);</pre> + +<div class="note"> +<p><strong>注</strong>: <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/random-color-eventobject.html">こちら</a> に GitHub上のサンプルがあります (また、<a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/random-color-eventobject.html">こちら</a>で実際に動くところが見れらます)。</p> +</div> + +<p>イベントオブジェクト <strong>e</strong> が関数に含まれていて、関数内で <code>e.target</code> — これはボタンそのもの — の背景色スタイルを設定しているのがわかるでしょう。イベントオブジェクトの <code>target</code> プロパティは、常にイベントが生じた要素への参照となっています。ですからこの例ではページではなくボタンの背景色がランダムに変わります。</p> + +<div class="note"> +<p><strong>注</strong>: イベントオブジェクトには好きな名前を使えます — イベントハンドラー関数のカッコの中に使いたい名前を書くだけです。<code>e</code>/<code>evt</code>/<code>event</code> が開発者の間でとても良く使われていますが、これらが短くて覚えやすいからです。標準に従うのはいつだって良いやり方です。</p> +</div> + +<p>複数の要素に同じイベントハンドラを割り当てて、どれかでイベントがあったときに何かさせたいような場合、<code>e.target</code> はとてつもなく有用なものです。複数の要素に同じイベントハンドラーを割り当てて、どれかでイベントがあったときに何かさせたいような場合、e.target はとてつもなく有用なものです。例えばクリックすると見えなくなるタイルが 16 個あるとします。<code>e.target</code> を使ってそれをただ消せるなら、もっと難解な手段で選びだすのよりも使いすいでしょう。続く例では (完全なソースコードは <a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/useful-eventtarget.html">useful-eventtarget.html</a> を見てください; ここで <a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/useful-eventtarget.html">ライブ実行</a> も見られます)、16 個の {{htmlelement("div")}} 要素を JavaScript で生成します。そしてこれらを全部 {{domxref("document.querySelectorAll()")}}を使って選択し、ループで一つ一つに <code>onclick</code> ハンドラを追加して、それぞれがクリックされた時にランダムな色が表われるようにしています:</p> + +<pre class="brush: js notranslate">const divs = document.querySelectorAll('div'); + +for (let i = 0; i < divs.length; i++) { + divs[i].onclick = function(e) { + e.target.style.backgroundColor = bgChange(); + } +}</pre> + +<p>結果はこうです(クリックして遊んでみてください):</p> + +<div class="hidden"> +<h6 id="Hidden_example" name="Hidden_example">Hidden example</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Useful event target example</title> + <style> + div { + background-color: red; + height: 100px; + width: 25%; + float: left; + } + </style> + </head> + <body> + <script> + for (let i = 1; i <= 16; i++) { + const myDiv = document.createElement('div'); + document.body.appendChild(myDiv); + } + + function random(number) { + return Math.floor(Math.random()*number); + } + + function bgChange() { + var rndCol = 'rgb(' + random(255) + ',' + random(255) + ',' + random(255) + ')'; + return rndCol; + } + + const divs = document.querySelectorAll('div'); + + for (let i = 0; i < divs.length; i++) { + divs[i].onclick = function(e) { + e.target.style.backgroundColor = bgChange(); + } + } + </script> + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_example', '100%', 400) }}</p> + +<p>あなたが使うであろうイベントハンドラーのほとんどでは、イベントオブジェクトには標準的なプロパティと関数(メソッド)({{domxref("Event")}}を参照してください)だけがあります。もっと上級者向けハンドラーでは、動作に必要な追加データを保持するために特殊なプロパティを付与するものもあります。例えば <a href="/ja/docs/Web/API/MediaRecorder_API">Media Recorder API</a> には <code>dataavailable</code> イベントがあり、オーディオやビデオの録音や再生が終わって何か(保存したり再生したり)する準備ができたところで発火します。これに紐付く <a href="/ja/docs/Web/API/MediaRecorder/ondataavailable">ondataavailable</a> ハンドラーのイベントオブジェクトには録音・録画データを保持する data プロパティがあり、これを使って何かしらを行なえます。</p> + +<h3 id="Preventing_default_behavior" name="Preventing_default_behavior">標準の動作を抑制する</h3> + +<p>ときにはイベントに付随する標準動作を止めたい場合があるでしょう。一番よくあるのは、ウェブのフォーム、例えばカスタマイズした登録フォームです。詳細を入力し終えてサブミットボタンを押した時、普通の動作ではデータがサーバーの指定のページに送られて処理され、ブラウザーは"成功しました"ページ(や他に指定されていない場合、同様なページ)にリダイレクトされたりなんやらします。</p> + +<p>ユーザーが適切なデータを送信しなかった場合に問題が発生します — 開発者としてあなたはサーバーへのデータ送信を抑止し、どこに問題があってデータを適切なものにするにはどうすればいいのか示す、ユーザーへのエラーメッセージを表示したいことでしょう。ブラウザーの中にはフォームデータの自検証機能を備えたものもありますが、多くはないので、それには頼らず自前の検証機能を実装すべきです。簡単な例を見てみましょう。</p> + +<p>まず、あなたにあなたの姓と名を入力させる単純な HTML フォームです。</p> + +<pre class="brush: html notranslate"><form> + <div> + <label for="fname">First name: </label> + <input id="fname" type="text"> + </div> + <div> + <label for="lname">Last name: </label> + <input id="lname" type="text"> + </div> + <div> + <input id="submit" type="submit"> + </div> +</form> +<p></p></pre> + +<div class="hidden"> +<pre class="brush: css notranslate">div { + margin-bottom: 10px; +} +</pre> +</div> + +<p> さあちょっとした JavaScript です — ここでは <a href="/ja/docs/Web/API/GlobalEventHandlers/onsubmit">onsubmit</a> イベントハンドラー(フォームがサブミットされるとサブミットイベントが発火します)の中で、テキストフィールドが空かどうかテストするだけのとても簡単なチェックを実装します。もし空なら、イベントオブジェクトの <code><a href="/ja/docs/Web/API/Event/preventDefault">preventDefault()</a></code> 関数— これでフォームの送信を抑制します — を呼び、それからフォームの下にあるパラグラフに、何が問題なのかユーザーに伝えるためのエラーメッセージを表示します:</p> + +<pre class="brush: js notranslate">const form = document.querySelector('form'); +const fname = document.getElementById('fname'); +const lname = document.getElementById('lname'); +const para = document.querySelector('p'); + +form.onsubmit = function(e) { + if (fname.value === '' || lname.value === '') { + e.preventDefault(); + para.textContent = 'You need to fill in both names!'; + } +}</pre> + +<p>言うまでもなく弱っちいフォームの検証です — 例えばフォームに空白や数字が入っていても止められません — が、例としては十分です。結果はこうなります。</p> + +<p>{{ EmbedLiveSample('Preventing_default_behavior', '100%', 140, "", "", "hide-codepen-jsfiddle") }}</p> + +<div class="note"> +<p><strong>メモ</strong>: ソースコード全体については、<a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/preventdefault-validation.html">preventdefault-validation.html</a> (及び <a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/preventdefault-validation.html">ライブ実行</a>も) をご覧ください。</p> +</div> + +<h3 id="Event_bubbling_and_capture" name="Event_bubbling_and_capture">イベントのバブリングとキャプチャリング</h3> + +<p>ここで最後に説明していくのは、滅多には遭遇しませんが、理解できていないととても苦痛になるかもしれない事柄です。ある一つの要素で同じイベントに紐付く二つのハンドラが活性化された時に何が起きるのかを説明するのが、イベントのバブリングとキャプチャリングという二種類のメカニズムです。わかりやすくするために次の例を見てください — <a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/show-video-box.html">show-video-box.html</a> 例を新しいタブで開いてください (<a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/show-video-box.html">ソースコード</a> もまた別のタブに)。ライブでも下で見られます:</p> + +<div class="hidden"> +<h6 id="Hidden_video_example" name="Hidden_video_example">Hidden video example</h6> + +<pre class="brush: html notranslate"><!DOCTYPE html> +<html> + <head> + <meta charset="utf-8"> + <title>Show video box example</title> + <style> + div { + position: absolute; + top: 50%; + transform: translate(-50%,-50%); + width: 480px; + height: 380px; + border-radius: 10px; + background-color: #eee; + background-image: linear-gradient(to bottom, rgba(0,0,0,0), rgba(0,0,0,0.1)); + } + + .hidden { + left: -50%; + } + + .showing { + left: 50%; + } + + div video { + display: block; + width: 400px; + margin: 40px auto; + } + + </style> + </head> + <body> + <button>Display video</button> + + <div class="hidden"> + <video> + <source src="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/events/rabbit320.mp4" type="video/mp4"> + <source src="https://raw.githubusercontent.com/mdn/learning-area/master/javascript/building-blocks/events/rabbit320.webm" type="video/webm"> + <p>Your browser doesn't support HTML5 video. Here is a <a href="rabbit320.mp4">link to the video</a> instead.</p> + </video> + </div> + + <script> + + const btn = document.querySelector('button'); + const videoBox = document.querySelector('div'); + <span style="background-color: #000044; color: #ffffff;">const </span>video = document.querySelector('video'); + + btn.onclick = function() { + displayVideo(); + } + + function displayVideo() { + if(videoBox.getAttribute('class') === 'hidden') { + videoBox.setAttribute('class','showing'); + } + } + + videoBox.addEventListener('click',function() { + videoBox.setAttribute('class','hidden'); + }); + + video.addEventListener('click',function() { + video.play(); + }); + + </script> + </body> +</html></pre> +</div> + +<p>{{ EmbedLiveSample('Hidden_video_example', '100%', 500, "", "", "hide-codepen-jsfiddle") }}</p> + +<p>これは内に {{htmlelement("video")}} 要素を含む {{htmlelement("div")}} を表示したり隠したりするとても簡単な例です。</p> + +<pre class="brush: html notranslate"><button>Display video</button> + +<div class="hidden"> + <video> + <source src="rabbit320.mp4" type="video/mp4"> + <source src="rabbit320.webm" type="video/webm"> + <p>Your browser doesn't support HTML5 video. Here is a <a href="rabbit320.mp4">link to the video</a> instead.</p> + </video> +</div></pre> + +<p>{{htmlelement("button")}} がクリックされると、<code><div></code> のクラス属性を <code>hidden</code> から <code>showing</code> に変更するので、ビデオが表示されます(例の CSS にこの二つのクラスが含まれており、それぞれはボックスの位置をスクリーンの外、内にします)。</p> + +<pre class="brush: js notranslate">btn.onclick = function() { + videoBox.setAttribute('class', 'showing'); +}</pre> + +<p>では二つばかり <code>onclick</code> イベントハンドラーを追加します — 最初のは <code><div></code> に、二つ目は <code><video></code>にです。ビデオの外側の <code><div></code> 領域がクリックされた時にはボックスがまた隠れるようにし、ビデオそのものがクリックされたらビデオが再生されるようにしたいというわけです。</p> + +<pre class="notranslate">videoBox.onclick = function() { + videoBox.setAttribute('class', 'hidden'); +}; + +video.onclick = function() { + video.play(); +};</pre> + +<p>が、ここで問題が — 今度はビデオをクリックすると再生が始まりますが、それと同時に<div>が隠されるようになってしまいました。ビデオが <code><div></code> の中にあるので(ビデオは div の一部ですから)、ビデオのクリックは上に挙げた両方のイベントハンドラーを実際に動かします。</p> + +<h4 id="Bubbling_and_capturing_explained" name="Bubbling_and_capturing_explained">バブリングとキャプチャリングの説明</h4> + +<p>親要素を持つ要素 (このケースでは {{htmlelement("video")}} です) においてイベントが発火すると、モダンブラウザーは二つの異なる段階に分けて動作します — キャプチャリングする段階とバブリングする段階です。</p> + +<p><strong>キャプチャリング</strong>の段階で行われることは……</p> + +<ul> + <li>要素の最上位の親要素 ({{htmlelement("html")}} に <code>onclick</code> イベントハンドラーがキャプチャリング段階に登録されているか調べ、あればそれを実行します。</li> + <li>次に <code><html></code> 要素の内側の要素に移って同じ事をし、また次の内側の要素にと、実際にクリックされた要素に到達するまで繰り返されます。</li> +</ul> + +<p><strong>バブリング</strong>の段階では、全く逆の事が起きます。</p> + +<ul> + <li>ブラウザーは実際にクリックされた要素の <code>onclick</code> イベントハンドラーがバブリング段階に登録されていれば、それを実行します。</li> + <li>次に直上の親要素に移動して同じ事をし、また次へ、<code><html></code> 要素に到達するまで繰り返します。</li> +</ul> + +<p><a href="https://mdn.mozillademos.org/files/14075/bubbling-capturing.png"><img alt="" src="https://mdn.mozillademos.org/files/14075/bubbling-capturing.png" style="display: block; height: 452px; margin: 0px auto; width: 960px;"></a></p> + +<p>(大きな図を見るにはクリックしてください)</p> + +<p>モダンブラウザーのデフォルトでは、全てのイベントハンドラーはバブリング段階に登録されます。ですのでこの例の場合では、ビデオをクリックするとクリックイベントは <code><video></code> 要素から外側の <code><html></code> 要素に進んで (バブリングして) いきます。従って:</p> + +<ul> + <li><code>video.onclick...</code> ハンドラーがあるので実行し、最初ビデオが始まります。</li> + <li><code>videoBox.onclick...</code> ハンドラーがあるので実行し、よってビデオも隠されます。</li> +</ul> + +<div class="blockIndicator note"> +<p><strong>記</strong>: 両方のイベントハンドラーが存在する場合バブリングとキャプチャリングでは、キャプチャフェーズが最初に走り、バブリングフェーズが続きます。</p> +</div> + +<h4 id="Fixing_the_problem_with_stopPropagation" name="Fixing_the_problem_with_stopPropagation()">stopPropagation()で問題を解決する</h4> + +<p>困った動作ですが、解決する方法があります! 標準的なイベントオブジェクトには <code><a href="/ja/docs/Web/API/Event/stopPropagation">stopPropagation()</a></code>という関数があって、ハンドラーのイベントオブジェクトで起動されると、このハンドラーは実行されますが、イベントが上位に伝播しないようにするので、これ以上のハンドラーは実行されなくなります。</p> + +<p>よって我々の今の問題は、先のコードブロック、第二のハンドラー関数をこのように変更して解決できます:</p> + +<pre class="brush: js notranslate">video.onclick = function(e) { + e.stopPropagation(); + video.play(); +};</pre> + +<p><a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/show-video-box.html">show-video-box.html ソースコード</a>のローカルコピーを作成してみて、自分で修正してみるか、修正された結果は <a href="http://mdn.github.io/learning-area/javascript/building-blocks/events/show-video-box-fixed.html">show-video-box-fixed.html</a> で見ることができます (こちらで<a href="https://github.com/mdn/learning-area/blob/master/javascript/building-blocks/events/show-video-box-fixed.html">ソースコード</a>も見られます)。</p> + +<div class="note"> +<p><strong>メモ</strong>: なんだってキャプチャリングとバブリングなんてあるのか? それはね、むかーしむかしの悪き時代、ブラウザーに今ほど互換性がなかった頃、ネットスケープはキャプチャリングだけを、IE はバブリングだけを使っていたのさ。W3C が動作について標準化と合意を作ろうと決めた時、結局どっちもシステムに入れることにし、モダンブラウザーはそのように実装されたのさ。</p> +</div> + +<div class="note"> +<p><strong>メモ</strong>: 上で述べたように、デフォルトでイベントハンドラーはバブリング段階に登録され、そしてほとんどの場合はこれが妥当です。もし本当にイベントをキャプチャリング段階の方に登録したいのであれば、<code><a href="/ja/docs/Web/API/EventTarget/addEventListener">addEventListener()</a></code>を使って、省略可能な第三引数に <code>true</code> を指定すれば実現できます。</p> +</div> + +<h4 id="Event_delegation" name="Event_delegation">イベントの移譲</h4> + +<p>バブリングでは<strong>イベント移譲</strong>という機能も活用できます — イベント移譲という概念は、たくさんある子要素のどれかしらがクリックされた際に何らかのコードを実行したいという場合に、個々の子要素一つ一つにイベントリスナーを設定するのではなく、親要素のイベントリスナーを設定すれば子要素のイベントリスナーからバブリングしてくるという事実に依拠しています。</p> + +<p>良い例としては、一連のリストアイテムです — どれかがクリックされたらメッセージをポップアップさせたいときには、親の <code><ul></code> 要素の <code>click</code> イベントリスナーに設定すれば、イベントはリストアイテムからバブリングしてきます。</p> + +<p>この概念はより深く David Walsh のブログで、たくさんの例とともに解説されています。— <a href="https://davidwalsh.name/event-delegate">How JavaScript Event Delegation Works</a> を見てください</p> + +<h2 id="スキルをテストしよう!">スキルをテストしよう!</h2> + +<p>この記事の最後に来ましたが、最も大事な情報を覚えていますか? 次に移動する前に、さらなるテストでこの情報を保持しているか検証できます — <a href="https://wiki.developer.mozilla.org/ja/docs/Learn/JavaScript/Building_blocks/Test_your_skills:_Events">Test your skills: Events</a> を見てください。</p> + +<h2 id="Conclusion" name="Conclusion">結論</h2> + +<p>ウェブイベントについて、今の学習初期段階で知るべき事は全部わかったはずです。上で述べたように、実のところイベントは JavaScript のコアには属しません — それらはブラウザーの Web API に属するものです。</p> + +<p>また重要な事は、JavaScript の使われ方によって異なるイベントモデルがありうる事も理解しておいてください — Web API とブラウザーの WebExtension や Node.js (サーバーサイド JavaScript) のような領域とでは。今あなたがそれらの領域について理解しなくてよいと思っていますが、ウェブ開発の事を学んでいくのにイベントの基礎を理解するのが役立つのは確かです。</p> + +<p>理解できない事があれば、気楽にまた記事を読み返したり、<a href="/ja/Learn#Contact_us">私達</a> に質問してください</p> + +<h2 id="See_also" name="See_also">関連情報</h2> + +<ul> + <li><a href="http://www.quirksmode.org/js/events_order.html">Event order</a> (キャプチャとバブリングの議論) — Peter-Paul Koch による非常に詳細な作品。</li> + <li><a href="http://www.quirksmode.org/js/events_access.html">Event accessing</a> (イベントオブジェクトに関する議論) — Peter-Paul Koch によるもう 1 つの非常に詳細な作品。</li> + <li><a href="/ja/docs/Web/Events">イベントリファレンス</a></li> +</ul> + +<p>{{PreviousMenuNext("Learn/JavaScript/Building_blocks/Return_values","Learn/JavaScript/Building_blocks/Image_gallery", "Learn/JavaScript/Building_blocks")}}</p> + +<h2 id="In_this_module" name="In_this_module">このモジュール</h2> + +<ul> + <li><a href="/ja/docs/Learn/JavaScript/Building_blocks/conditionals">コードでの意思決定 — 条件文</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Building_blocks/Looping_code">ループコード</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Building_blocks/Functions">関数 — 再利用可能なコードブロック</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Building_blocks/Build_your_own_function">独自の関数を作る</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Building_blocks/Return_values">関数の戻り値</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Building_blocks/Events">イベントの紹介</a></li> + <li><a href="/ja/docs/Learn/JavaScript/Building_blocks/Image_gallery">イメージギャラリー</a></li> +</ul> |