search phpbb-phpbb-FC2BLOG-Info-Edit Template-Post-Edit-Upload-LogOut
jQuery.js の Event 処理を理解するためには、関連するインスタンスメソッドから呼び出される各種のクラスメソッドや、その中から呼び出される関数を理解しなければなりません。というよりも、Event 関連の全てのインスタンスメソッドが直接・間接的にクラスメソッドを呼び出して定義されているので、jQuery.event クラスメソッドを理解しなければ jQuery.js のイベント処理は全く理解出来ないでしょう。
併せて、jQuery.event クラスメソッドから呼び出される jQuery クラスメソッドも理解しなければなりません。
そこで、ここでいうクラスメソッド等が何を指しているのか、まず明らかにする必要があります。
なお、「イベントハンドラー」という言葉は、イベントオブジェクトを操作するための3つのオブジェクトのセット──イベントタイプ、dataオブジェクト及びイベントハンドラー関数──を指しています。
以後のエントリイにおいて、以上のメソッドを全て解読する予定ですが、まずこのエントリイでは add() メソッドと、それを理解するために不可欠な $.data() クラスメソッドを解読します。
タイトルで言うところの「 ver 1.2.2 における若干の改訂 」とは、 $.event.special プロパティの新設(mouseenter/leave 等への対応など)とセットになったイベントバインドに係る部分の変更を指しています。
以下で言う「中域」とは独自に作った用語で、所謂 global でもなく、かといって地域変数でもない名前空間です。それは jQuery.js コード全体を包含する無名関数内における最上位の名前空間を意味しています。他に適当な言葉が見つからないため「中域」としました。
中域変数は jQuery .js 内においてどこからでも利用できる変数であり、同時に jQuery.js 内のメソッドや関数を利用し終えた後にはメモリから消え去り、利用することが出来ない変数です。
jQuery.js 内ではこの空間を Namespaced Spaceと呼んでいます。
中域などと造語せずに、「jQuery名前空間」と呼ぶのが最適かも知れません。
さて、このメソッドは jQuery.js のイベント処理のスタートを切り、かつ根幹を為すメソッドです。このメソッドがイベントハンドラーを目的とする要素に bind(登録)するからです。
1804: add: function(elem, types, handler, data) {
//elem がテキストノードとコメントノードだった場合には何もしない。
1805: if ( elem.nodeType == 3 || elem.nodeType == 8 )
1806: return;
1807:
//IE バグ対策として引数 elem を window とする。
//なお、window だけではなく各要素の setInterval メソッドが利用出来
//ない IE とは、どのバージョンなのかは調べ切れていない。
1808: // For whatever reason, IE has trouble passing the window object
1809: // around, causing it to be cloned in the process
1810: if ( jQuery.browser.msie && elem.setInterval != undefined )
1811: elem = window;
1812:
地域変数 handler(つまりイベントハンドラー関数)に、ユニークな番号(guid:1 から始まる整数値)を振る。この結果 guid の最終値は、当該頁においてユーザーが登録したイベントハンドラー関数の数マイナス1を表すことになる。(guid には post-increment演算子が利用されているので、値は式適用後には加算されるため)
1813: // Make sure that the function being executed has a unique ID 1814: if ( !handler.guid ) 1815: handler.guid = this.guid++; // =jQuery.event.guid 1816:
/* data が与えられている時には function(){fn.apply(this, arguments);} を
* handler に代入し、handler の data プロパティに data を、guid プロパティ
* に guid を、各々代入する。
* ここで行っていることは、かなり回りくどい方法を取っているが、要は
* 引数 data オブジェクトの引数 handler 関数オブジェクトへの関連づけである。
* また handler は後述するように、指定した DOM ノードに type イベントと
* セットになって bind 済みのイベントハンドラー関数であり、イベントハンド
* ラーリストに登録された関数となる。
1817: // if data is passed, bind to handler
1818: if( data != undefined ) {
1819: // Create temporary function pointer to original handler
1820: var fn = handler;
1821:
1822: // Create unique handler function, wrapped around original handler
1823: handler = function() {
1824: // Pass arguments and context to original handler
1825: return fn.apply(this, arguments);
1826: };
1827:
1828: // Store data in unique handler
1829: handler.data = data;
1830:
1831: // Set the guid of unique handler to the same of original handler, so it can be removed
1832: handler.guid = fn.guid;
1833: }
/* 第一引数として add() の elem を、第二引数として文字列 "events"を与えて
* $.data() メソッドを実行する。しかし、この結果は undefined となり、論理演算
* 子 || の働きで、続けて jQuery.data(element, "events", {}) が実行される。
* こうして jQuery.cache[ id ][ "events" ] に {} が代入され、この空オブジェク
* トが地域変数 events にも代入される。
* ここに、id とは $.data() によって定義される uuid 番号であり、イベントが
* 登録された各々の element 要素に対応する固有の整数値となる。
* また jQuery.cache[ id ][ "events" ] は、これ以降のコードによってイベント
* 名やイベントハンドラー関数をそのプロパティとして保有することになるオブ
* ジェクトである。
* いずれにせよ、この部分は $.data() クラスメソッドが分からないと全く理解出来
* ない。そこでエントリイ後半で $.data() クラスメソッド について解読する。
*/
1835: // Init the element's event structure
1836: var events = jQuery.data(elem, "events") || jQuery.data(elem, "events", {}),
/* 次も$.data()メソッドを利用しているので、ここでは結論だけを記す。
* jQuery.data(element, "handle", function(){・・・} により、地域変数 handle
* には jQuery.cache[ id ][ "handle" ] が代入される。ここの id 番号は 上の
* events に代入された jQuery.cache[ id ][ "events" ] の id と同じ値である。
* また、jQuery.cache[ id ][ "handle" ] には 1837-1849行までの無名関数が
* 登録される。
*/
1837: handle = jQuery.data(elem, "handle") || jQuery.data(elem, "handle", function(){
1838: // returned undefined or false
1839: var val; // 地域変数 val の初期値を undefined 又は false とする。
1840:
// jQuery が未定義か、triggered が true ならば undefined か false
// を返す。こうして、これらのケースの場合に新規のイベントの bind
// (登録)が行わなわれないようにしている。
1841: // Handle the second event of a trigger and when
1842: // an event is called after a page has unloaded
1843: if ( typeof jQuery == "undefined" || jQuery.event.triggered )
1844: return val;
1845:
/* element 要素上で、jQuery.event.handle() メソッドを実行する関数を 地域変数
* valに代入する。ここでは apply メソッドが実行される訳ではなく、定義され代
* 入されるだけである。ここに、上の if が成立しなければ、つまり
* typeof jQuery != "undefined" && !jQuery.event.triggered ならば
* 1846 行で val 値に代入された関数が、1848 行により地域変数 handle に
* return される。この val に代入された関数は、イベント発生時に、そのハンド
* ラー関数を選択・確定し、実行するメソッド jQuery.event.handle() メソッド
* を呼び出す働きをする。
*/
1846: val = jQuery.event.handle.apply(arguments.callee.elem, arguments);
1847:
1848: return val;
1849: });
/* 次のブロックは ver 1.2.1 ではなかった。
* elem をハンドラー関数のプロパティに代入している。
* メモリーリークを避けるため、と記されているが、この一行が必要となる具体的
* な現象や理由は不明にして分からない。
*/
1850: // Add elem as a property of the handle function
1851: // This is to prevent a memory leak with non-native
1852: // event in IE.
1853: handle.elem = elem;
1854:
/* ver1.2.2 から一度に複数のイベントタイプを登録出来るようになった。
* 1856 行はその例示である。
* これにより、同一ハンドラー関数を同一要素の複数イベントタイプに登録したい
* 場合に、少し簡潔なコード記述が出来るようになった。
*/
1855: // Handle multiple events seperated by a space
1856: // jQuery(...).bind("mouseover mouseout", fn);
/*「Namespaced event handlers」という言葉が登場するが、これは jQuery名前空間
* 内のイベントハンドラーとでも訳すのが最適だろう。
* ver1.2 以降の jQuery.js においては、グローバル変数である jQuery 内に、
* イベントを制御するために、data() メソッドを駆使して jQuery 固有の機構を設け
* た。それは jQuery.cache オブジェクト内の様々なプロパティを通じてイベント
* ハンドラーを管理するものである。
* ここでは、その1つの準備としてカスタムイベントを制御するためのプロパティ
* として handler 関数に type プロパティを定義し、その値にカスタム type
* 文字列を代入している。
*/
1857: jQuery.each(types.split(/\s+/), function(index, type) {
1858: // Namespaced event handlers
// type 文字列から" . "を分割文字として配列を作る。
1859: var parts = type.split(".");
1860: type = parts[0]; //地域変数 type に type 文字列を代入する
//カスタム type 文字列を、handler 関数の type プロパティに代入する。
1861: handler.type = parts[1];
1862:
/* 当該イベントに既に登録されたイベントハンドラー関数のリストを地域変数
* handlers に代入する。
* ここでも $.data() を理解しないと events[type] の具体的な意味は分からない。
* events[type] は 1836 行の data() メソッドによって生成されるからである。
* そして、1875-1878行が実行されない限り、(つまりイベントの登録が終わらな
* い限り)events[type] は undefined となり、その時には空オブジェクトを代入
* する。これにより当該要素ノードへの type 名別にイベントハンドラー関数を管
* 理する。
*/
1863: // Get the current list of functions bound to this event
1864: var handlers = events[type];
1865:
1866: // Init the event handler queue
1867: if (!handlers) {
1868: handlers = events[type] = {};
1869:
ver1.2.2 における Event 関連コードの大きな改訂の1つはこの部分である。
jQuery.event.special プロパティを新設し、中でブラウザ別に mouseover/out と mouseenter/leave を使い分けているのだが、1873 行はそのことと一体となっている。
この部分では jQuery.event.special に type プロパティが存在しないか、または elem.jQuery.event.special[type].setup() メソッドの返値が false の場合にだけ Listener()などを作動させるようにしている。
まず、special オブジェクト内に存在する type 名は ready と mouseenter/leave だけ(2126-2179)なので、その他の type 名のイベントの時には、1875 行以下が実行される。またブラウザが IE の時には setup()メソッドから false が返されて attachEvent() メソッドが実行される。
他方、IE 以外のブラウザの場合には、複雑な過程を辿る。 setup() メソッド内で、 mouseenter は mouseover に、mouseleave は mouseout に各々イベントタイプ名を変更し、かつ $.event.special.handler()メソッドをハンドラー関数として設定してから、bind() メソッドが再帰呼び出しされる。当然 bind()メソッドからは add() メソッドが再帰呼び出しされるので、二重の入れ子構造で処理を行うことになる。
この入れ子構造における処理過程は、別途 special() メソッド解読で詳細に述べることとする。
1870: // Check for a special event handler
1871: // Only use addEventListener/attachEvent if the special
1872: // events handler returns false
1873: if ( !jQuery.event.special[type] || jQuery.event.special[type].setup.call(elem) === false ) {
1874: // Bind the global event handler to the element
1875: if (elem.addEventListener)
1876: elem.addEventListener(type, handle, false);
1877: else if (elem.attachEvent)
1878: elem.attachEvent("on" + type, handle);
1879: }
1880: }
1881:
/* 登録済みの handler 関数を固有番号に登録する。
* 1864 行により handlers = events[type] だから、1883 行は
* handlers = events[type][handler.guid] = handler ; となる。
* 1888 行では type 名のイベントが登録されたことを global プロパティに記録
* させている。
*/
1882: // Add the function to the element's handler list
1883: handlers[handler.guid] = handler;
1884:
1885: // Keep track of which events have been used, for global triggering
1886: jQuery.event.global[type] = true;
1887: });
1888:
/* 最後にまたしても I E対策である。
* メモリリークを避けるために elem を空ににしている。
*/
1889: // Nullify elem to prevent memory leaks in IE
1890: elem = null;
1891: },
jQuery.js は jQuery(args) によって、DOMエレメント集合を要素とする配列を取得します。例えば var tmp = jQuery("p") とすれば、変数 tmp には当該頁の全てのPエレメントノードをその要素とする配列が代入されます。
jQuery.js は、この取得配列から個別のエレメントノードを特定し操作するために、jQuery("p").index(num) や jQuery("p").get(num) などのインスタンスメソッドを用意しています。
また、Pエレメントノードに class 属性が設定すれば jQuery("p.className").get(num) 等により絞り込むことも出来ます。
しかし、これらの既定のメソッドでは、異なる名称のエレメントノードの、(単なる属性ではなく)特定の性質を有する要素集合内の、各要素を特定するには大変面倒な指定が必要となります。そこで考案されたメソッドが $.data() であり、$.remodeData() なのだと、推量します。
このメソッドは find() メソッド内や filter() メソッド内で、第一引数のみを取る data(elment) 形式で利用され id 番号の取得に利用されていますが、これら以外の箇所では全て event を処理するために、2番目以降の引数を与えて使用されています。ですから、このメソッドは event 処理のために導入されたと言っても過言ではないでしょう。
さて、data() メソッドは大変抽象的な内容です。そこで、具体的な内容を知るには event 処理コードにおいてそれが実際に使用されたケースや、その結果としての DOM ツリーを調べることが早道なのではないか、と考えました。実際そうしてみてやっとこのメソッドが理解できたのです。なお、data() メソッドと対を為している removeData() メソッドは 別途取り上げる予定なので、以下では data() メソッドのみを取り上げます。
或る Web 頁において、複数のイベントハンドラーを jQuery.js を使って登録し、その直後の DOM ツリーを見てみました。以下の DOM ツリーは jQuery.cache オブジェクトの load イベントと mousemove イベントに係る部分を抜き出したものです。
さて cache オブジェクト内の様々なプロパティは data() メソッドにより作成されたものです。uuid 番号はイベントが登録されたエレメントノードに対応し、それぞれの uuid オブジェクトが必ず2つ──events 及び handle──のプロパティを有しています。そして events オブジェクトは必ず1つ以上のイベントタイプ名のプロパティを持ち、その中に既に bind 済みのイベントハンドラー関数が guid 番号を振られて登録されています。
つまり jQuery.data() メソッドによって作成される jQuery.cache オブジェクトは、必ず
jQuery.cache[uuid]["events"][event.type][guid] = event handler function
のような構造となります。
$ ↓uuid ↓guid └ cache object ├ 1 object //$.data(elm,name) により振られた $(elm) に対応する uuid 番号1のオブジェクト | ├ events object //$.data(elm,"events") によって設定されたオブジェクト | | └ load object //イベントタイプ名のオブジェクト | | ├ 1 function //引数 handler で与えられ、guid番号 1 を割り振られた bind 済みの 関数 | | |├ guid 1……1560 行で付与された番号 | | |├ data undefined……引数 data が付与された場合のdata | | |└ type undefined……eventtype.custum と指定された場合の custum値 | | └ 7 function //引数 handler で与えられ、guid番号 7 を割り振られた bind 済みの 関数 | | ├ guid 7 | | ├ data undefined | | └ type undefined | └ handle function //$.data(elm,"handle") によって設定された関数オブジェクト ├ 2 object //特定の Elementノードに対応する data() により振られた uuid 番号2のオブジェクト | ├ events object //data() において name値=eventsで設定されたオブジェクト | | └ mousemove object //イベントタイプ | | └ 2 function //引数 handler で与えられ、guid番号 2 を割り振られた bind 済みの 関数 | | ├ guid 2 | | ├ data undefined | | └ type undefined | └ handle function //$.data(elm,"handle") によって設定された関数オブジェクト ├ 3 ・・(以下略)
/* 中域変数 expando に当該 jQuery.js ファイルが読み込まれた時の時刻を
* 記録し、中域変数 uuid(universal unique ID)と 同 win を初期化する。
* これらの変数は jQuery.js 内の各種メソッドから随時呼び出されて利用さ
* れる。このため uuid は決して重複せず、++uuidにより呼び出される度に
* 1ずつ加算される、異なる整数値を提供する。
*/
588: var expando = "jQuery" + (new Date()).getTime(), uuid = 0, win = {};
/* jQuery.cache を空オブジェクトとして定義する。このオブジェクトの中に
* 各種の情報を登録していき、それによるイベントハンドラーの管理を可能
* としている。
*/
640: cache: {},
/* data()メソッド開始
* elem が window の場合にはこれを変数 windowData に置き換える。
* 次に elem の expando プロパティを 地域変数 id に代入する。
* しかし、当該 elem に最初に data() メソッドを適用した場合には
* このプロパティは存在しないから id 値は null 値となる。
* 一方 elem[ expando ] が存在している場合にはその値がそのまま
* id 値となる。
*/
642: data: function( elem, name, data ) {
643: elem = elem == window ?
644 windowData :
645 elem;
646:
647: var id = elem[ expando ];
648:
/* 或る element に最初に data メソッドを適用した場合には id は null
* 値なので、地域変数 id と elem オブジェクトの expando プロパティに
* uuid 番号を代入する。
* id が存在すれば( 同じ element に対して二回以上 data メソッドを
* 適用した場合等)何もしない。
*/
516: // Compute a unique ID for the element
517: if ( !id )
518: id = elem[ expando ] = ++uuid;
519:
// name 引数が存在し、かつ jQuery.cache オブジェクトの id 属性が存在
// しなければ jQuery.cache オブジェクトの id 属性に空オブジェクトを登録する。
653: // Only generate the data cache if we're
654: // trying to access or manipulate it
655: if ( name && !jQuery.cache[ id ] )
656: jQuery.cache[ id ] = {};
657:
// dataが定義されていれば
// jQuery.cache[ id ][ name ]プロパティに data を代入する。
// data が未定義の場合 jQuery.cache[ id ][ name ] は未定義となる。
658: // Prevent overriding the named cache with undefined values
659: if ( data != undefined )
660: jQuery.cache[ id ][ name ] = data;
661:
// name引数があれば jQuery.cache[ id ][ name ] を、なければ id 値を返す。
// この結果 name があって data がない場合には未定義値 undefined が返される。
662: // Return the named cache data, or the ID for the element
663: return name ?
664: jQuery.cache[ id ][ name ] :
665: id;
666: },
90%近いシェアを握っているインターネットエクスプローラの描画エンジンを利用したタブbrowser。沢山のタブbrowserがあるが、多機能、カスタマイズフリー、スクリプト利用等で一日の長がある。Gekkoエンジンへの対応も行われ、IEからの自立独立の方向に向かっている。2005年7月にはIE7が登場する見通しの中で、今後の発展が望まれる。
多様なCSS作成支援機能を備えた、タグ入力式 HTML&CSS作成支援エディタ。スキンデザインもすっきりしている。テキストエディター上で作成するよりも確実で安全にタグ打ちが出来る。
文字コードを選べないのが欠点。
StyleNote同様のタグ入力式 HTML&CSS 作成支援エディタ。長年使用してきたが現在StyleNoteに乗り換えつつある。
クリップボード履歴情報を活用する為のソフト。画像まで履歴を取ってくれるのが嬉しい。このソフトを使わない日は絶対ない程に重宝し、愛用している。
起動中のウィンドウの「コピーできない」説明文などの文字列を取得し、コピー可能な文字データにするツール。何かと便利。
ストリーミングデータを保存することが出来るソフト。動画利用には不可欠なソフトだ。
無料ながらレイヤー機能を有し、スクリプトによる拡張も可能な、sleipnir作者が提供している優れもの画像編集ソフト。
画面キャプチャソフトと言えばこれに勝るものなし、ではないだろうか? 様々な取得方法を有しており、ブログ作成にもHomepage作成に不可欠だ。Jtrimと並んでWoodyBellsの作品。
複数ファイルの同時編集は出来ないが、透過pngも作れる画像編集ソフト。
(以下当該サイトから抜粋)初心者にも簡単に操作が出来るフォトレタッチソフトです。多くの加工機能で画像に様々な効果を与えることができます。非常に軽快に動作するため、ストレスなく操作できます。
Animation Gifファイルを作れる無料ソフト。
キャプチャソフト。画面内にサイト全体が表示しきれない場合でも、これを使えば全体をキャプチャすることが出来る。
画像処理。画像のフォーマット変換のみならず、色数やサイズ、圧縮率の変更まで一括処理できてしまう『BatchGOO!』は、大量の画像をまとめて処理したいときに大変便利なソフト。BMP, TIFF, JPEG, PCX, PNG の相互変換をはじめ、色数・サイズ・解像度の統一、JPEG圧縮率の調節など、ホームページ用の画像や携帯電話用の壁紙を揃えるのに抜群の相性を見せる。(Vectorの当該ソフト紹介頁より抜粋引用)
名前から直ぐに想像が付くように画像のサイズを測るためのソフトだ。Homepage作成には欠かせない。2カラム、3カラムのレイアウトを行う場合に大変重宝する。
ランチャーソフトは沢山あるが、中でもこれが一押しだ。2年以上使ってきたがその操作性には毎日満足している。これを使い始めてからデスクトップには一切のアイコンを表示することをやめてしまった。
AdobeReader7によって、起動時間が長すぎるという長年のユーザーの不満はある程度解消した。そのためこの高速化ソフトは存在価値が低下してしまったかもしれない。AdobeReader6迄はこのソフトによる起動高速化で恩恵を受けてきた。
IE専用が難点だが、様々なサイト内でIDやパスワードを入力するのに重宝するソフト。コンテキストメニューから簡単に起動できるのがGood! sleipnir等のIEの描画エンジンを利用しているブラウザでも使える。
利用しているパソコンの諸元値を取得するには、このソフトがベストだ。インストール済みソフトの一覧が取得できるのも嬉しい。
WMPは機能が豊富なだけ重い。RealPlayerも同様だ。そこでMedia Player Classicを使いたい。動作が軽快なだけではなく、対応しているファイル形式もすこぶる多く、これひとつで、wmvもrmも表示できてしまうのだから凄い! 数多あるMedia Playerの王様と言えるだろう。
自宅でPCを起動しているときには必ず起動しているメディアプレーヤー。何かと過剰なWinampよりも、起動も速くスキンはシンプルだ。
DivX, Xvid, Mov, Vob, Mpeg, Mpeg4, avi, wmv, dv, などの動画をDVD-Video形式に変換できるフリーソフト。クリックするとDVD関連ソフト紹介サイト=「DVDなToolたち」なるHomepageが開きます。