More Related Content
Similar to DOMイベントの基礎から深淵まで (20)
DOMイベントの基礎から深淵まで
- 3. 中野雅之
• 肩書き
• 正式: Mozilla Japan 国際化担当マネージャ
• 半公式: Mozilla Japan ジョギング部大阪支部長
• 非公式: Mozilla Japan 大阪支部長
• 大阪の自宅で、自宅警備しながら仕事してます
- 4. 中野雅之
• 色んなアカウント
• メールアドレス: masayuki@d-toybox.com
• Skype: masayuki-nakano
• Twitter: @d_toybox
• Facebook: masayuki.nakano.560
• Blog: 「もずはっく日記」で検索
- 5. アジェンダ
• DOM イベントの仕様って?
• DOM イベント処理の基礎
• DOM Level 4でのイベント生成
• 各入力イベントのふかーーーーーーいお話
- 7. DOM イベントの仕様
• ユーザの入力や、他の仕様に左右されないイベント
• Document Object Model (DOM) Level 2 Events Specification
• W3C Recommendation 13 November, 2000
• Document Object Model (DOM) Level 3 Events Specification
• W3C Editor's Draft 04 September 2012
• DOM4 Events
• Unofficial Draft
- 8. DOM イベント処理の基礎
• フェイズと、プロパゲーション
• addEventListener()と、removeEventListener()
• 複数のイベントリスナ
• stopPropagation()と、preventDefault()
• trustedイベントと、untrustedイベント
• init*Event()
• event constructor
- 9. フェイズとプロパゲーション
• DOM イベントには4つの状態がある
フェイズ: イベントが、イベントターゲットに向け
• Capture
てルートから順に発生していく状態
フェイズ: イベントが、イベントターゲット上で発
• Target
生している瞬間
フェイズ: イベントが、イベントターゲットで発生
• Bubble
した後、ルート要素まで順に遡ってイベントが再度発生
していく状態
• 状態無し:
イベントをDispatchする前の状態や、ハンド
ラで捕まえたイベントを変数に保存している状態
- 13. addEventLister()と
removeEventListener()
属性でもイベントはハンドリングできるけど、
• on*
addEventListener()とremoveEventListener()の利用推
奨
• 一つのイベントターゲットに対して、複数のハンドラを登
録できる
• Capture フェイズのイベントも捕まえられる
• コードが、なんとなくカッコイイ。
- 14. addEventLister()と
removeEventListener()
• 書式:
• EventTarget.addEventListener(
イベント名, ハンドラ, Capture?);
• EventTarget.removeEventListener(
イベント名, ハンドラ, Capture?);
• イベント名: イベントの名前 "click" とか、 "keydown"
• ハンドラ: function foo(aEvent) { /* something */ } がお手軽で十分
• Capture?: true なら、Capture フェイズと、Target フェイズ、false
なら、Target フェイズと、Bubble フェイズ
- 16. addEventLister()と
removeEventListener()
• 単純な例2:
• 全ての要素で発生するkeydownイベントを知りたい
• イベントターゲットより後に知りたい
• removeする必要がある
function keydownHandler(aEvent) { /* something */ }
document.addEventListener("keydown",
keydownHandler, false);
…
document.removeEventListener("keydown", keydownHandler, false);
- 18. 複数のイベントリスナ
• 先にaddEventListener()を利用して登録されたものが優
先される。
• もずはっく日記の実例でテストすると以下の結果に
• 親要素のcaptureフェイズに最初に登録されたハンドラ
• 親要素のcaptureフェイズに二番目に登録されたハンドラ
• イベントターゲットのbubbleフェイズに最初に登録されたハンドラ (captureへの登録よ
りも前)
• イベントターゲットのbubbleフェイズに二番目に登録されたハンドラ (captureへの登録
よりも前)
• イベントターゲットのcaptureフェイズに最初に登録されたハンドラ
• イベントターゲットのcaptureフェイズに二番目に登録されたハンドラ
• イベントターゲットのbubbleフェイズに三番目に登録されたハンドラ (captureへの登録
より後)
• イベントターゲットのbubbleフェイズに四番目に登録されたハンドラ (captureへの登録
より後)
• 親要素のbubbleフェイズに最初に登録されたハンドラ
• 親要素のbubbleフェイズに二番目に登録されたハンドラ
- 22. trustedイベントと、untrustedイベント
イベントとは、ユーザの入力や、要素の状態の
• trusted
変化等で、自然に発生したイベントのこと。isTrusted属
性がtrue。preventDefault()を呼ばない限り、ブラウザの
デフォルトアクションが必ず発生する
イベントとは、Webアプリケーションが、
• untrusted
document.createEvent()で作り出した、人工的なイベン
ト。isTrusted属性はfalse。セキュリティ等の問題から、
trusted イベントでは発生する、ブラウザのデフォルトアク
ションの発生は期待できない。発生するかは実装依存
- 24. init*Event()
interface Event
{
void initEvent(DOMString typeArg,
boolean canBubbleArg,
boolean cancelableArg);
};
interface UIEvent
{
void initUIEvent(DOMString typeArg,
boolean canBubbleArg,
boolean cancelableArg,
AbstractView viewArg,
long detailArg);
};
- 25. init*Event()
interface MouseEvent
{
void initMouseEvent(DOMString typeArg,
boolean canBubbleArg,
boolean cancelableArg,
AbstractView viewArg,
long detailArg,
long screenXArg,
long screenYArg,
long clientXArg,
long clientYArg,
boolean ctrlKeyArg,
boolean altKeyArg,
boolean shiftKeyArg,
boolean metaKeyArg,
unsigned short buttonArg,
EventTarget relatedTargetArg);
};
- 26. init*Event()
• はい、もう無茶苦茶感が出てきましたね。他のインタ
ーフェース紹介をやめて、
MouseEvent.initMouseEvent()の実例を見てみましょう。
myEvent.initMouseEvent("click", true, true, null, 1, 300, 450,
200, 250, true, false, false false, 1,
null);
• 分かるかボケー、と思った方の感覚が普通です!
- 27. event constructor
4 Events では、event constructorという初期化方
• DOM
法が提案されていて、実際、Geckoでは一部イベントで
すでに利用可能
• JSON形式の初期化方法で、イベントが定義する、デフ
ォルト値と違う属性だけを初期化すれば済む
var myEvent = new MouseEvent("click",
{ bubbles: true, cancelable: true,
detail: 1, button: 1,
screenX: 300, screenY: 450,
clientX: 200, clientY: 250,
ctrlKey: true });
- 29. Synthesized mousemove イベント
• Synthesized mousemove イベントとは?
• 正式に仕様書等に出てくる用語ではなく、Geckoのソースコー
ドから名付けました
• 名前の通り、カーソルの動きに関係無く、生成された
mousemove イベント
• マウスカーソルがドキュメントの上に有る状態で、スクロール
した後に、新しい要素の上で発生するmousemoveイベント
• WebKitと、Operaで発生。Geckoは内部イベントとしては存在
するものの、Webアプリからは検知できず
• WebKit、Opera共にモディファイアキーの状態は不適切なので
要注意
- 33. レガシーマウスホイールイベント
• "mousewheel" イベント
• Gecko以外のエンジンでは採用されているレガシーイベント。
• wheelDelta 属性にスクロールの値が入っているものの、その
値については厳密な定義は見当たらず
• Windows版、IEとChromeは、ネイティブイベントのデルタ値を
単純に設定してる模様
• Windows版、Operaは、1行スクロールするにあたり、40を設
定する模様
• Mac等では未調査
• WebKit以外では縦方向のホイールイベントしか発生しない
• とにかく、定義不明で使いにくいのが問題
- 34. レガシーマウイホイールイベント
• "DOMMouseScroll" イベント
• Geckoのみが実装
• detail属性値が、スクロールする行数
• 高解像度スクロールが後にWindowsとMacで採用され
てしまったため、これをpreventDefault()するだけでは、
スクロールを完全に抑制することができなくなっている
- 36. D3E "wheel" イベント
では、WheelEvent インターフェースの、"wheel" イベ
• D3E
ントが定義された
• 現在、IEとGeckoが実装済み
• 斜め方向へのスクロールも一つのイベントで表現できるよ
うになった(ただし、ネイティブイベントの制約上、Macのみ)
• deltaX、deltaY、deltaZがそれぞれの軸にそったスクロー
ル量で、longではなく、double
• deltaModeで、deltaX、deltaY、deltaZのスクロール量が、
ページ単位、行単位、ピクセル単位のどれであるかを表現
- 37. D3E "wheel" イベント
• 残念ながらWebKitでは実装が行われていない
• Operaでも実装されていない
• Geckoの場合、delta値が実際にデフォルトアクションでス
クロールする量と必ずしも一致しない(あくまで、Webアプリ
ケーションに対する、スクロールして欲しい量の目安と考え
て)
• Geckoの場合、ユーザ設定でスクロール量を増やすと、
delta値も増えるので、ゲームの主要な入力要素としては
使えない
- 41. getModifierState()
• D3Eで、MouseEventと、KeyboardEvent、WheelEventに定義されて
いるメソッド
• IEとGeckoが対応。WebKitはまだ?
• パラメータにモディファイアキー名を入力する
• そのイベント生成時に押されていれば、true、押されていなければfalse
• モディファイアキー名は、"Shift"、"Control"、"Alt"、"Meta"、"AltGraph"、
"CapsLock"、"NumLock"、"ScrollLock"、"SymbolLock"、"Fn"、"OS"
• IEでは、"ScrollLock"の代わりに、"Scroll"、"OS"の代わりに、"Win"が
使われている
• IEでは、MouseEventと、KeyboardEventで検出できるモディファイア
キーの状態に差がある
- 43. CompositionEvent
• IMEの未確定文字列入力時、確定時に発生するイベント
• "compositionstart" 入力開始。data属性値は未確定文字列で
置換される文字列
• "compositionupdate" 未確定文字列が変更された場合に発生。
data値は最新の未確定文字列
• "compositionend" 確定。data値は確定された文字列
• 仕様上は"compositionupdate"のdata値のみを監視すると、未
確定文字列が分かるはずだが、WebKitは"compositionstart"の
data値が最初の未確定文字列の値なので、面倒なことになって
いる
• "compositionupdate"の発生タイミングは、IEはエディタの内容
が更新された後、GeckoとWebKitは更新される前。input要素や、
textarea要素のvalue値に注意
- 45. KeyboardEvent.key and .char
• KeyboardEvent、実は標準化されるのは、D3Eが初めて(予定)
• .keyCodeはブラウザ依存の値を持っていて、今更統一、国際化
対応が困難
• .charCodeは入力された文字のUnicodeのcode pointが入って
いるものの、使いづらい
• これらを解決するために、 .keyと .charが新たに提案された
• どちらの値もDOMStringになっていて、扱い易くなっている
• IEが既に実装していて、その内容がほぼそのままドラフトに掲載
されている
- 46. KeyboardEvent.key and .char
• 文字入力用ではないキーでは、.charはおおむね、空文
字列(例外あり)、 .keyは、仕様で定義済みのキーの名
前か、UAが命名できる場合はそれでも良い
• 後者の仕様はWebデザイナが地獄を見ることになるの
で大問題
• 必要なのに定義済みキー名に無いものは、多々、W3C
のbugzillaへ登録しまくっている最中
- 47. KeyboardEvent.key and .char
• 文字入力用のキーでは、.charは、文字が入力される場
合の文字列、 .keyは、.charと同じ値
• .keyと .charが同じ値なら意味がない
• .charが、実際に文字が入力されない場合にも入ってい
るのでは、Webアプリが独自のテキストエディタを作り
にくい
- 48. KeyboardEvent.key and .char
• 現在、Mozillaから提案している(予定含む)改善案
• .keyの定義済みキー名を増やす
• 未定義の .key名を利用する場合はprefixをつけるべき
• .keyの動作はそのままに、.charは実際にそのイベント
でテキストエディタで入力される値にする
• 例えば、Ctrl+Cだと、.key = "c"、.char=""