技 巧 鍵 盤 ─ KeyNavi:キーボードを活用してホームページを快適に─    
キー割当表示[Shift-H]        
ホーム KeyNavi対応方法 [0] JavaScript@Keynavi.Netトップ [1] イベントハンドラの登録 ・サイトマップ [Shift-S]

■ イベントハンドラの登録:kl_addhandler()

イベントハンドラの登録について説明します。 マウスが押された(mousedown)時のイベント処理をするとして話を進めます。

ハンドラ関数登録時の問題点
Mozilla系ブラウザでは「document.addEventListener(...)」とできますが その他のブラウザでは「document.onmousedown=myfunc;」などと関数を代入する形で 登録するのが普通です。

後者の方法では既にイベントハンドラが登録されている場合に 既存のものを上書きしてしまう問題があります。 例えば <body onmousedown="oldfunc()">などとHTML内で 既に指定がある場合 これによって上書きされてしまうため 「oldfunc()」は実行されないことになります。

また第三者の作ったJavaScriptモジュール内で 「window.onload=oldfunc;」という記述がある場合も同様です。

そこで「kl_addhandler()/delhandler()」 という関数を用意しました。以下のような特徴があります。

「kl_addhandler()/delhandler()」の特徴
- HTMLタグ内 及び他のスクリプトで予め指定されたハンドラを上書きせず。 新たに追加するものと合わせ両方動く。
- ブラウザの種類に関わらずハンドラ関数の第一引き数には 「event」オブジェクトが入る。 (New!)
Netscpae4,6,7,Mozilla系ブラウザだけでなく IE,Operaでも第一引き数をイベント オブジェクトとして扱えます。
- ハンドラ関数に任意個数の引き数を渡せる。 (New!)
通常のハンドラ関数はイベント引き数しか無く タイマー利用時と同じく変数の退避先に困る場合があります。 詳しくは ハンドラ関数の引き数指定機能を使ってみる (このページ内)
- 関数の代わりに実行文字列を渡すこともできる。 (New!)
→処理内容をHTMLのタグ内の記述と同じようにも書けます。
- 関数内では「this」で登録先のHTML要素を参照できる。 (New!)
MozllaのaddEventListener()はOKですが IE5+のattachEvent()では「this==window」となっているので「this」が使えません。
- 追加したハンドラは削除できる。
- Netscape4の場合はcaptureEvents/releaseEventsを内部で実行してくれる。 自分で記述する必要が無い。
- kl_hashandler()でハンドラ関数が登録済みかどうか確認できる。
- クロスブラウザ。
IE4-6、NS4,6,7、Opera6-7、Mozilla。

具体的には以下のケースで効果的です。

「kl_addhandler()/delhandler()」が有用なケース
- 誰か別の人が作ったJavaScriptが既にあり自分が作ったものと両方動かしたい。 その時に既存のHTML、スクリプトは書き替えたくない。
- 機能をモジュール化し各モジュール内で独立してイベントハンドラを登録したい。
- デザイン(HTML,CSS)とロジック(JavaScript)を分離したい。
デザイナーには当該タグでid指定のみしてもらえばJavaScriptからもハンドラが 「追加」登録できる。デザイナーとプログラマーが同時並行で仕事を進められる。

【イベントハンドラの登録「kl_addhandler()」<keynavi_ja.js】

-------------------------------------------------------------------------------
■ kl_addhandler(o,etype,func,args,ns4capture)
・返り値:1
・o:登録先のオブジェクト
・etype:イベントの種類 (onload,onkeydown,onfocus,onblur,..)
・func:登録する関数オブジェクトかその名前
・args:引き数配列(funcの第2引き数以下に充当:略可)
・ns4capture:Netscape4でcaptureEvents(Event...)を実行するか否か
              "auto"&指定無しの時は「etype=onload」以外で実行
■ kl_delhandler(o,etype,func,args,ns4capture)
・返り値:削除に成功(func,argsが一致)した数(通常は1)
・ns4capture:Netscape4でreleaseEvents(Event...)を実行するか否か

■kl_clearhandler(o,etype)
・既存のハンドラを全てクリアします

■kl_hashandler(o,etype,func,args)
・ハンドラ関数が登録済みなら真を返す
-------------------------------------------------------------------------------
function kl_addhandler(o,etype,func,args,ns4capture){
        //Opera7は「self」「window」へのハンドラ登録は内部的に「document」属性扱いにする為以下
        if(KL_OP7) if(o==self) o=document;

        //func=実行文字列だったら関数に
        func=kl_isstr(func) ? (new Function("e",func)) : func;
        args=kl_isarray(args) ? args : new Array();

        //NS4の場合フラグns4capture次第でo.captureEvents(Event...)を実行
        if(KL_NS4) kl_ah_ns4(ns4capture,o,etype,0);

        kl_ah_add(o,etype,func,args);
        kl_ah_update(o,etype);
        return 1;
}
function kl_delhandler(o,etype,func,args,ns4capture){
        if(KL_OP7) if(o==self) o=document;
        args=kl_isarray(args) ? args : new Array();
        var cnt=kl_ah_del(o,etype,func,args);
        kl_ah_update(o,etype);
        if(KL_NS4) kl_ah_ns4(ns4capture,o,etype,1);
        return cnt;
}
。。。略。。。

NS4用引き数:ns4capture
通常、Netscape4.xでは「o.captureEvents(Event.イベント名)」を実行しないと レイヤーや画像に対するイベントを拾えません。 明示的に実行したい場合は 真に設定して下さい。 注意することとして「etype="onload"」に対して実行すると ページ全体だけでなく各レイヤーのHTMLや画像が読まれるたびに 登録関数がよばれます。 そこで「ns4capture="auto" or 指定無し」の場合は通常 「captureEvents/removeEvents」を実行するものの 引き数が「o==window(self) & etype="onload"」の場合には 実行しないよう工夫しています。 殆どの場合、引き数「ns4capture」は指定不要です。

「kl_addhandler()」では イベントハンドラを追加するたびに 当該要素の属性として関数や引数情報を保持します。 イベント発生時には登録された全てのハンドラ関数が実行されます。

もし「kl_addhandler()」を実行した時点で 別のJavaScriptモジュールやタグ内記述によるハンドラ指定があっても それらは内部的に保持され並行実行されるのでOKです。

複数のハンドラ関数が指定された場合の処理
ハンドラ関数の実行は登録の旧いものから順に行われます。 通常、登録された関数は全て実行されますが 関数内で「e.kl_skip=1」とすると後続は処理はされません。 また どれか一つの関数でも「false」を返すとハンドラ関数全体の 返り値としてブラウザに「false」が渡されます (→ブラウザ既定のイベント処理を抑える事ができます)。

【kl_addhandler()を使ったサンプル:Copy&Paste】

<script language="javascript" src="http://www.keynavi.net/files/keynavi_ja.js"></script>
<script language="javascript"><!--
function down(e){ self.status="mousedown: ("+kl_mousex(e)+","+kl_mousey(e)+")"; }
kl_addhandler(document,'onmousedown',down);
//-->
</script>

mousedownハンドラが上書きされないか確認してみる
以下のスクリプトではマウスボタンが押された時に カーソルのページ内座標をステータスバーに表示するようにしています。

上の実行ボタンを押した後、ページ内をクリックしてステータスバーを 見てみてください。 マウス座標が表示されるはずです。

次はハンドラが上書きされてないか確かめてみましょう。 KeyNaviでは「自動モード(G/T)」の実行を 任意キー以外にマウスクリックでも停止できるようにしています。 「T(戻る)」「G(進む)」を押して自動モードにし ページ内の任意位置をマウスクリックしてみて下さい。

自動モードの停止とマウス位置の表示の両方が実行されるはずです。

既存スクリプトとKeyNaviの共存
KeyNaviでは 「document.onkeydown/ onkeypress/ onkeyup/ onmousedown」と 「window.onload/ onresize」 に対しイベントハンドラを登録しています。 そのため上書きの問題が生じます。

これらにハンドラを指定したい場合、 「kl_addhandler()」を使えばKeyNaviのハンドラ関数は上書きされません。

一方、既にハンドラ指定を含むJavaScriptコードがある場合は KeyNaviの指定 <script language="javascript" src=".../keynavi_ja.js"></script> をそれらの後に置きます。

そうすると KeyNaviのハンドラ関数は後から追加される形になるので 既存スクリプトとKeyNaviの両方が動作してくれます。 よく分からない場合は KeyNaviのタグ指定を 全ての既存スクリプトの後に置くようにすれば無難です。 殆どのブラウザでは</html>の後ろにおいても 動作します。

ハンドラ関数の引き数指定機能を使ってみる
一般にイベントハンドラとして登録される関数内からは 1.唯一の引き数=イベントオブジェクト、 2.「this」=登録先HTML要素、 3.大域的名前空間 しか アクセスできません。

ハンドラ関数内から上記以外のオブジェクトにアクセスしたい場合 大域変数を用意したり 個別にハンドラ関数を作ったりという 手間がかかるのが普通です。

setTimeout(),setInterval()などタイマー利用時も 実行文字列や関数にローカル変数を渡せないため類似の問題が生じています。 タイマー機能を簡単に利用:kl_timer_...()

Layer0
 
Layer1
Layer1
 

上の例では 「lay1」「lay2」をクリックしたら 「lay0」の背景色がそれぞれ 赤、青に変わります。

ハンドラ関数「f()」はイベントオブジェクト「evt」以外に 「lay」「color」を引き数として受け取り そのまま背景色を変更をしています。

一般的な方法では ハンドラ関数「f()」に対し 引き数としてイベントオブジェクトしか渡せません。 その結果 関数内から変更対象の「lay0」や変更色「color」を参照できません。 そのため これらをグローバル変数にするなど 回り道が必要になります。 特に同じような組合せが任意個数、任意変数ある場合には対応がメンドウになります。

「kl_addhandler()」の引き数指定機能はこのようなケースで 特に有効です。 レイヤーのドラッグ設定・解除:kl_drag_set() ,レイヤークリックで手前に移動:kl_raise_set() ではレイヤーObjectを渡すのに使っています。

Netscape4ではレイヤー内に画像がある場合、 画像にもハンドラを指定する必要があります(動的にレイヤーを作成した場合など)。

画像が無い部分をクリックした場合は 関数内からのレイヤー参照に「this」が使えるのですが 画像上をクリックした時は「this」が画像になるため 困ります。 そこでハンドラ関数登録時にレイヤーオブジェクトを引き数として渡しています。




【JavaScript@Keynavi.Net : 一般イベント処理編 】
「Ctrl-矢印」でフォーカスを上下左右に移動できます。

  - マウス位置取得:kl_mousex,y()
  - Focus/Click先の要素を取得:kl_target()
  - イベントハンドラの登録:kl_addhandler()
  - ページ全体に対するイベントハンドラの登録
  - レイヤーにイベントハンドラを登録
  - フォームやリンクにイベントハンドラを登録

トップへ戻る [1]
ホーム KeyNavi対応方法 [0] JavaScript@Keynavi.Netトップ [1] イベントハンドラの登録 ・サイトマップ [Shift-S]
キー割当表示[Shift-H] ─ KeyNavi Project 2003 ─