ホームページ  >  記事  >  ウェブフロントエンド  >  jQuery イベント binding_jquery の原理に関する簡単な説明

jQuery イベント binding_jquery の原理に関する簡単な説明

WBOY
WBOYオリジナル
2016-05-16 16:22:35956ブラウズ

jq には、関連するデータを DOM 要素にバインドする data メソッドがあります。 jq メソッドを使用してイベントが dom にバインドされると、対応する時刻リストが生成されます
次の例を確認できます (Firefox のオブジェクトは toSource() をサポートしているため、Firefox で表示してください)

コードをコピーします コードは次のとおりです:



<頭>










data はデータを要素にバインドするために使用されます
データソースはキャッシュオブジェクトです
要素がデータにバインドされると、属性 jQueryxxx が要素に追加されます。xxx は jq
を実行したときのタイムスタンプです。 ここで説明させてください。累積的な uuid があります
jQueryxxx の値はこの uuid
です キャッシュキーはこのuuid
です value は保存するデータです
データはイベント バインディングにとって非常に重要です................................

コードをコピー コードは次のとおりです:

function now(){
    新しい日付を返します。 
};
var win = これ,
    Expando = "jQuery" now(),
       uuid = 0,
      キャッシュ = {};
win.data = function(elem, name, data){
    var id = elem[展開]; 
    if(!id)
        id = elem[expando] = uuid; 
    if(名前&&!キャッシュ[id])
        キャッシュ[id] = {}; 
    if(データ !== 未定義)
        キャッシュ[id][名前] = データ; 
    名前を返します
        ?キャッシュ[id][名前]
        : ID; 
}
win.removeData = function(elem, name){
    var id = elem[展開]; 
    if (名前){
        if (キャッシュ[id]) {
            キャッシュ[id][名前]を削除します。 
            名前 = ""; 
            for ( キャッシュ内の名前[ id ] )
                壊す; 
            if ( !name )
                削除データ(要素); 
        }
    }その他{
            {
を試してください                 要素を削除[展開]; 
            } catch(e){
                if ( elem.removeAttribute )
                    elem.removeAttribute(expando); 
            }
            キャッシュ[id]を削除します。 
    }
}

win.each = function( object, callback, args ) {
    変数名、i = 0、長さ = object.length; 
    if ( args ) {
        if ( 長さ === 未定義 ) {
            for ( オブジェクト内の名前 )
                if ( callback.apply( object[ name ], args ) === false )
                    壊す; 
        } else
            for ( ; i                 if ( callback.apply( object[ i ], args ) === false )
                    壊す; 
    } else {
        if ( 長さ === 未定義 ) {
            for ( オブジェクト内の名前 )
                if ( callback.call( object[ name ], name, object[ name ] ) === false )
                    壊す; 
        } else
            for ( var value = object[0];
                私は<長さ && callback.call( value, i, value ) !== false;値 = オブジェクト[ i] ){}
    }
    オブジェクトを返します。 
}



次に、イベントの追加を実装します

jq には jQuery.event の add メソッドがあります
一部の関数は add メソッド
で実装されています。 要素のイベントを取得し、これら 2 つのデータにバインドされたデータを処理します
events はイベントのリストを保存します
形式は次のとおりです
{
クリック: [{handler:function(){},type:"click",guid:'xx'}....],
マウス:[...]
}
ハンドルは実行された関数です
(すべての実行関数は同じです。イベント リストを走査し、対応するイベントを実行します)
次に、複数のイベントをバインドできるため、タイプを走査します
コールバック関数はいくつかの属性も与えます
コールバック関数が handler
であると仮定します。 handler.guid = gevent.guid
handler.type = 名前
name は、簡単に削除できるように特別な名前として考慮する必要があります
たとえば
$('#xx')
.bind('クリック',function(){})
.bind('click.d',ハンドラー)
名前はd
です 削除する場合、上記のクリックイベントは削除せず、dイベントのみ削除できます

最後に、イベントは要素にバインドされますが、実行される関数はすべて
function(){
gevent.handle.apply(arguments.callee.elem, argument);
});

コードをコピー コードは次のとおりです:

win.gevent = {
ガイド: 1、
追加: 関数 (要素、型、ハンドラー){
If (elem.nodeType == 3 || elem.nodeType == 8)
return;
if ( elem.setInterval && elem != window )
elem = window;
//後でイベントを削除しやすくするために、関数に一意のインデックスを与えます
if ( !handler.guid )
handler.guid = this.guid;
// 要素
のイベント ハンドルの下にあるデータを取得します var events = data(elem, "events") || data(elem, "events", {}),
ハンドル =data(elem, "ハンドル") || data(elem, "ハンドル", function(){
//gevent.handle は、さまざまな動作がトリガーされた後に実行される関数です
gevent.handle.apply(arguments.callee.elem, argument);
});
handle.elem = elem;
//マウスオーバーでクリックできるため、イベント名をトラバースします
Each(types.split(/s /), function(index, type) {
var namespaces = type.split(".");
//イベント名を取得
type = namespaces.shift();
//ポイント以降を削除 削除する場合はclick.d
のように指定して削除します。 //イベント タイプを使用してこの特別な名前を記録します
handler.type = namespaces.slice().sort().join(".");
// イベントがイベント オブジェクトに既に存在するかどうかを取得します
var handlers = events[type];
// イベントが存在しない場合は、イベントを要素にバインドします if (!handlers) {
ハンドラー = イベント[タイプ] = {};
If (elem.addEventListener)
elem.addEventListener(type, handle, false);
else if (elem.attachEvent)
elem.attachEvent("on" type, handle); }
//関数を要素のイベントリストに入れます
handlers[handler.guid] = ハンドラー; });
要素 = null; }
}


gevent.hander はバインドされたイベント
によって実際に実行される関数です gevent.hander にも特別な名前を付ける場所がありますが、それが何に使われるのかわかりません
イベントは最初にハンドラー
にパッケージ化されます。 パッケージ化については、gevent.fix と setEvent
を参照してください。 主なことは、ネイティブ イベントのコピーを作成し、互換性のないメソッドを互換性のある記述に結合することです
次に要素
のイベント(イベントリスト)を取得します。 次に、イベント リストを走査して、type がイベント リストのキーであるかどうかを判断し、そうであれば、イベント
を実行します。 戻り値はリスト関数実行時に判定されます
false を返す場合、イベントのバブリングとデフォルトの動作を整理することもできます

コードをコピー コードは次のとおりです:

win.gevent = {
ハンドル:関数(イベント){
var all、ハンドラー;
//パッケージングイベント
イベント = 引数[0] = gevent.fix(event || window.event );
event.currentTarget = this;
//ここ...
var namespaces =event.type.split(".");
event.type = namespaces.shift();
all = !namespaces.length;
var namespace = RegExp("(^|\.)" namespaces.slice().sort().join(".*\.") "(\.|$)");
//この要素の動作のイベントリストを取得します
ハンドラー = (data(this, "events") || {} )[event.type]; //このイベント リストを調べて、実行すべきものを実行します
for ( var j in handlers ) {
var handler = handlers[j];
If ( すべて || namespace.test(handler.type) ) {
// ハンドラー関数自体への参照を渡します
// 後で削除できるようにします
// jq のコメントは、便宜上このイベントへのイベント ハンドラーを参照し、後で削除します
// しかし、ここでイベントハンドラーが何に使われるのかわかりません。また、複数のイベントがある場合、このイベントは置き換えられます。 event.handler = ハンドラー;
//イベントを実行します。これは要素で呼び出されるイベントです。イベント内でこの要素を実行できます。ret は関数
の戻り値です。 var ret = handler.apply(this, argument);
//戻り値があり、戻り値が false の場合、実行によりイベントのバブリングが妨げられ、実行イベントのデフォルトの動作がブロックされます。 If( ret !== 未定義 ){
event.result = ret;
If ( ret === false ) {
event.preventDefault();
event.stopPropagation();
}
                                                                                                                                                                                                            }
}、
props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget datadetaileventPhase fromElement handler keyCode metaKey newValueoriginalTarget pageX pageY prevValue relationshipNode relationshipTarget screenX screenY SHIFTKey srcElement target toElement view WheelDelta where".split(" "), 修正: function(event){
//new setEvent はイベントに Expando 属性を与えます。いずれかの属性がある場合は、イベントが生成されており、イベントを再度ラップする必要がないことを意味します
if (event[expando] )
リターンイベント;
//オリジナルのイベントを保持します
// new 新しいイベントです。元のイベント
とは異なります。 varoriginalEvent = イベント;
イベント = 新しい setEvent(originalEvent);
//元のイベントの属性値を取得します。どのような属性値があるかについては、this.props
を参照してください。 for ( var i = this.props.length, prop; i; ){
prop = this.props[ --i ];
イベント[ prop ] = OriginalEvent[ prop ];
}
//対象要素をevent.target
に統合する If ( !event.target )
event.target =event.srcElement || srcElement が定義されていない可能性がある #1925 を修正します
//テキストノードであることが判明した場合は、その親ノードを取得します
If (event.target.nodeType == 3 )
event.target =event.target.parentNode;

If ( !event.popularTarget &&event.fromElement )
イベント.関連ターゲット = イベント.fromElement == イベント.ターゲット ? イベント.toElement : イベント.fromElement; return イベント;
                                             }
win.setEvent = function(src){
// 'new' キーワードなしでインスタンス化を許可します
// イベントオブジェクト
If( src && src.type ){
This.originalEvent = src;
This.type = src.type;
// イベントタイプ
}その他
This.type = src;
// Firefox の一部のイベントではタイムスタンプにバグがあります(#3843)
// したがって、ネイティブ値には依存しません
This.timeStamp = now();
// 修正済みとしてマークします
This[expando] = true;
}
関数 returnFalse(){
false を返します;
}
関数 returnTrue(){
true を返します;
}
setEvent.prototype = {
PreventDefault: function() {
var e = this.originalEvent;
If( !e )
return;
//PreventDefault が存在する場合は、元のイベントで実行します
If (e.preventDefault)
e.preventDefault();
// それ以外の場合は、元のイベントの returnValue プロパティを false に設定します (IE)
e.returnValue = false;
}、
stopPropagation: function() {
var e = this.originalEvent;
If( !e )
return;
// stopPropagation が存在する場合は、元のイベントで実行します
If (e.stopPropagation)
e.stopPropagation();
// それ以外の場合は、元のイベントの cancelBubble プロパティを true に設定します (IE)
e.cancelBubble = true;
}、
stopImmediatePropagation:function(){
This.isImmediatePropagationStopped = returnTrue;
This.stopPropagation();
}、
isImmediatePropagationStopped: returnFalse
};


完全な例

コードをコピー コードは次のとおりです:

http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
http://www.w3.org/1999/xhtml">








<スクリプトタイプ="text/javascript">
(関数(ドキュメント,未定義){
function now(){
新しい日付を返します;
};
var win = これ,
Expando = "jQuery" now(),
uuid = 0,
キャッシュ = {};
win.data = function(elem, name, data){
var id = elem[expando];
if(!id)
id = elem[expando] = uuid;
if(名前&&!キャッシュ[id])
キャッシュ[id] = {};
if(データ !== 未定義)
キャッシュ[id][名前] = データ;
名前を返します
?キャッシュ[id][名前]
: id;
}
win.removeData = function(elem, name){
var id = elem[expando];
if (名前){
if (キャッシュ[id]) {
キャッシュを削除[id][名前];
名前 = "";
for ( キャッシュ内の名前[ id ] )
休憩;
if ( !name )
RemoveData(elem);
}
}その他{
{
を試してください delete elem[expando];
} キャッチ(e){
if ( elem.removeAttribute )
elem.removeAttribute(expando);
}
キャッシュ[id]を削除;
}
}
win.each = function( object, callback, args ) {
変数名、i = 0、長さ = object.length;
if ( args ) {
if ( 長さ === 未定義 ) {
for (オブジェクト内の名前)
if ( callback.apply( object[ name ], args ) === false )
休憩;
} 他
for ( ; i if ( callback.apply( object[ i ], args ) === false )
休憩;
} else {
if ( 長さ === 未定義 ) {
for (オブジェクト内の名前)
if ( callback.call( object[ name ], name, object[ name ] ) === false )
休憩;
} 他
for ( var value = object[0];
私は<長さ && callback.call( value, i, value ) !== false;値 = オブジェクト[ i] ){}
}
オブジェクトを返す;
}
win.gevent = {
guid : 1,
add : 関数 (要素、型、ハンドラー){
if ( elem.nodeType == 3 || elem.nodeType == 8 )
戻る;
if ( elem.setInterval && elem != window )
elem = ウィンドウ;
//関数数一唯一の标识的インデックス 方便后面删除该イベント
if ( !handler.guid )
handler.guid = this.guid ;
// この要素のイベント ハンドルの下のデータを取得します
var events = data(elem, "events") || data(elem, "イベント", {}),
ハンドル =data(elem, "ハンドル") || data(elem, "ハンドル", function(){
//gevent.handle才はさまざまな実行のための触発後の会議実行の関数
gevent.handle.apply(arguments.callee.elem, argument);
});
handle.elem = elem;
//遍历イベント名はマウスオーバーでクリックできるため
each(types.split(/s /), function(index, type) {
var namespaces = type.split(".");
//获得イベント名
type = namespaces.shift();
//去掉点後面の东西は特殊な命名 在删除的時間候指定可能删除他 例 click.d
//用イベントのタイプ记录住これ特殊な命名
handler.type = namespaces.slice().sort().join(".");
//このイベントが存在するかどうかを確認します。イベントが存在するかどうかを確認します。 var handlers = events[type];
//そのイベントが存在しない場合は、そのイベントを元素で決定します
if (!handlers) {
ハンドラー = イベント[タイプ] = {};
if (elem.addEventListener)
elem.addEventListener(タイプ、ハンドル、false);
else if (elem.attachEvent)
elem.attachEvent("on" タイプ, ハンドル);
}
//元素のこのイベントの列表面
に関数が割り当てられています handlers[handler.guid] = ハンドラー;
});
elem = null;
}、
削除: function(elem、types、handler) {
if ( elem.nodeType == 3 || elem.nodeType == 8 )
戻る;
// この要素のすべての行を列表にします {click:{},mouseocer:{}}
var events = data(elem, "events")、ret、index;
if(イベント){
// 行がタイプに含まれない場合は、この要素を削除するすべてのイベント
// 入力されたものが .xx である場合、この形式のすべての行には .xx 命名が含まれており、すべての障害が発生します
if ( タイプ === 未定義 || (タイプオブタイプ === "文字列" && タイプ.charAt(0) == ".") ){
for ( var type in events )
this.remove( elem, type (types || "") );
}その他{
//不知道干嘛的
if (types.type) {
ハンドラー = type.handler;
タイプ = タイプ.タイプ;
}
//删除イベントが一度にサポートできるため、マウスオーバーでクリックするなどすべて必要遍历删除
each(types.split(/s /),function(index, type){
var namespaces = type.split(".");
type = namespaces.shift();
var namespace = RegExp("(^|\.)" namespaces.slice().sort().join(".*\.") "(
\.|$)"); if ( イベント[タイプ] ) {
//如果传了第3个パラメータ関数関数 则删除このイベント
if ( ハンドラー )
イベントを削除[タイプ][ハンドラー.guid];
それ以外{
//遍历中のこのすべての行は
for ( events[type] の var ハンドル){
// 名前空間イベントの削除を処理します
//删除有特殊命名関数数
//特別な名前がない場合、正規表現は /^|..|$/ であり、空と一致するため、特別な名前のない関数も削除できます
if ( namespace.test(events[type][handle].type) )
イベントを削除[タイプ][ハンドル];
}
}
}
for ( ret in events[type] ) Break;
// events[type] が空になった場合、つまり、{} この要素のバインディング イベントを削除します
if ( !ret ) {
if (elem.removeEventListener)
elem.removeEventListener(type, data(elem, "handle"), false);
else if (elem.detachEvent)
elem.detachEvent("on" type, data(elem, "handle"));
ret = null;
イベントを削除[タイプ];
}
});
}
for (ret in events) Break;
//要素のすべてのイベントが空であることが判明した場合
// ハンドルをクリアし、その参照をすべてクリアします
if ( !ret ) {
var handle = data( elem, "ハンドル" );
if ( ハンドル ) handle.elem = null;
RemoveData( elem, "イベント" );
RemoveData( elem, "ハンドル" );
}
}
}、
ハンドル: 関数(イベント){
var all、ハンドラー;
//パッケージングイベント
イベント = 引数[0] = gevent.fix( イベント || window.event );
イベント.currentTarget = this;
//ここで....
var namespaces =event.type.split(".");
event.type = namespaces.shift();
すべて = !namespaces.length;
var namespace = RegExp("(^|\.)" namespaces.slice().sort().join(".*\.") "(\.|$)");
//この要素の動作のイベントリストを取得します
handlers = (data(this, "events") || {} )[event.type];
//このイベント リストを調べて、実行すべきものを実行します
for (ハンドラー内の変数 j) {
var handler = handlers[j];
if ( all || namespace.test(handler.type) ) {
// ハンドラー関数自体への参照を渡します
// 後で削除できるようにします
// jq のコメントは次のように記述されています。イベント ハンドラーは便宜上このイベントを参照します。後で削除できます。
// ただし、remove ではイベント ハンドラーは使用されず、イベントが複数ある場合はこのイベントが置き換えられます。 イベント.ハンドラー = ハンドラー;
//イベントを実行します。これは要素で呼び出されるイベントです。イベント内でこの要素を実行できます。ret は関数
の戻り値です。 var ret = handler.apply(this, argument);
//戻り値があり、戻り値が false の場合、実行によりイベントのバブリングが防止され、実行イベントのデフォルトの動作がブロックされます
if( ret !== 未定義 ){
イベント.結果 = ret;
if ( ret === false ) {
イベント.preventDefault();
イベント.stopPropagation();
}
}
}
}
}、
props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data Detail eventsPhase fromElement handler keyCode metaKey newValueoriginalTarget pageX pageY prevValue relationshipNode relationshipTarget screenX screenY SHIFTKey srcElement target toElement view WheelDelta what".split(" "),
修正: 関数(イベント){
//new setEvent はイベントに Expando 属性を与えます。いずれかの属性がある場合は、イベントが生成されており、イベントを再度ラップする必要がないことを意味します
if ( イベント[展開] )
リターンイベント;
//オリジナルのイベントを保持します
// new新しいイベント これは元のイベントとは異なります
varoriginalEvent = イベント;
イベント = 新しい setEvent(originalEvent);
//元のイベントの属性値を取得します。 this.props
を参照してください。 for (var i = this.props.length, prop; i; ){
prop = this.props[ --i ];
イベント[ prop ] = オリジナルイベント[ prop ];
}
//対象要素をevent.target
に統合する if ( !event.target )
event.target = events.srcElement || // srcElement が定義されていない可能性がある #1925 を修正します
//テキストノードであることが判明した場合は、その親ノードを取得します
if (event.target.nodeType == 3)
イベント.ターゲット = イベント.ターゲット.parentNode;
if ( !event.popularTarget &&event.fromElement )
イベント.関連ターゲット = イベント.fromElement == イベント.ターゲット ? イベント.toElement : イベント.fromElement;
リターンイベント;
}
}
win.setEvent = function(src){
// 'new' キーワードなしでインスタンス化を許可します
// イベントオブジェクト
if( src && src.type ){
this.originalEvent = src;
this.type = src.type;
// イベントタイプ
}その他
this.type = src;
// Firefox の一部のイベントではタイムスタンプにバグがあります(#3843)
// したがって、ネイティブ値には依存しません
this.timeStamp = now();
// 修正済みとしてマークします
this[expando] = true;
}
関数 returnFalse(){
false を返します;
}
関数 returnTrue(){
true を返します;
}
setEvent.prototype = {
PreventDefault: function() {
var e = this.originalEvent;
if( !e )
戻る;
//PreventDefault が存在する場合は、元のイベントで実行します
if (e.preventDefault)
e.preventDefault();
// それ以外の場合は、元のイベントの returnValue プロパティを false に設定します (IE)
e.returnValue = false;
}、
stopPropagation: function() {
var e = this.originalEvent;
if( !e )
戻る;
// stopPropagation が存在する場合は、元のイベントで実行します
if (e.stopPropagation)
e.stopPropagation();
// それ以外の場合は、元のイベントの cancelBubble プロパティを true に設定します (IE)
e.cancelBubble = true;
}、
stopImmediatePropagation:function(){
this.isImmediatePropagationStopped = returnTrue;
this.stopPropagation();
}、
isImmediatePropagationStopped: returnFalse
};
})(ドキュメント);
var $ = function(id){return document.getElementById(id)}
var a = function(){alert(1)}
window.onload = function(){
gevent.add($('xx'),'click',a);
gevent.add($('xx'),'click',function(){alert(1)});
gevent.add($('xx'),'click',function(){alert(2)});
gevent.add($('xx'),'click',function(){alert(3)});
gevent.add($('xx'),'click.xx',function(){alert(4)});
}


以上の内容は自己の一部理解、水平有限、难免有错、望指正...

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。