JavaScriptイベントパッケージ
11840 ワード
本編ではJavascriptのイベントメカニズムを振り返ってみます.同時に最小の関数から最後の完全な機能を持つ強力なイベントモジュールについて書き始める.記述の都合上、応答関数/コールバック関数/イベントListener/イベントhandlerをイベントhandlerと呼びます.
ページにイベントを追加するいくつかの方法
1.JSコードを直接HTMLに書く
2.関数を定義して、html元素のonXXX属性を与えます.
3.element.onXXX方式を使う
4.addEvent ListenerまたはatachEventを使用する
はい、方式4を簡単にパッケージして、標準ブラウザとIEブラウザに対応します.注意atachEventの最初のパラメータは「on」を追加する必要があります.addEvent Listenerの三つ目のパラメータはfalseであり、イベントの泡を表します.atachEventは第三のパラメータがありません.デフォルトでは泡が発生し、捕獲されません.
このページは対応する削除イベントの関数を追加します.前の篇の中でfnはIE 6/7/8の中で実際に包装されました.IE 6/7/8の中で本当のhandlerはel[e]+fnです.そのため削除する時に使うべきです.同時に二つの方法を一つのオブジェクトEにかけ、add、removeはそれぞれイベントを追加し、削除する.
イベントトリガー
はい、追加と削除の二つの方法があります.各ブラウザの下の部分的な違いを解決しました.アクティブトリガイベントを追加します.この方法は、クリック操作などのユーザの行動をシミュレートすることができる.標準はdispatch Event方法を使います.IE 6/7/8はfireEvent方法を使います.異常があるかもしれないので、try catchを使いました.
完全である
上のaddに問題があります.同じタイプのイベントに複数のhanderを追加すると、IE 6/7/8の下で無秩序になります.
今回は、すべての内部詳細を匿名関数にカプセル化し、この関数を実行した後、上記のインターフェースと同じ方法に戻ります.または、本当のイベントhandlerをelに掛け、つまりel.listenersを対象とし、各タイプのイベントは一連であり、例えばclickはel.listeners[click]=[]である. すべてのハンドルは対の配列に存在しています. は、handerを削除し、配列から を削除します.
一回だけ実行するイベントを追加する必要がある場合があります.このために、add方法に第4のパラメータoneを追加します.oneはtrueであると、このイベントはhandlerに一回だけ実行されます.要素タイプのすべてのモニターを削除します. 要素のすべてのモニターを削除します. 例えば、一つのlにclickイベントを3つ追加したhandler、一つのmouseoverイベントのhandler.
以下は元素にあるすべてのイベントを削除します.clickとmouseoverを含みます.E.remove(el).
上に正式に私のイベントモジュールイベントがあります.v 1は、最初のフレームを組み立てられています.多くのJSライブラリや枠組みに比べて、まだ事件の対象となる互換性がないという人もいるかもしれません.はい、わざとこれを後から補充します.事件の対象の互換性の問題が多すぎて、ややこしいです.
次に私は私有の_を導入します.fixEvent関数、addではこの関数を呼び出します._fixEventは元のイベントオブジェクトを修復し、標準的な統一インターフェースのイベントオブジェクトを返します.次のとおりですイベントのデフォルト行為を阻止し、e.preventDefaultを一括使用する() 発泡を停止し、e.stopPropagationを統一的に使用する() イベントソースを取得し、e.target を一括使用する..../li> もっと多くの差異性はここに挙げられません.
ページにイベントを追加するいくつかの方法
1.JSコードを直接HTMLに書く
<div onclick="alert(' Nowamagic.net');">Nowamagic</div>
HTML Elementの要素自体は多くのonXXX属性を持っています.JSコードを値付けすればいいです.OnXXXに与えられた文字列は応答関数の関数として機能します.たぶんこれは90年代の書き方です.JSコードを直接ホームページに書くのは普通です.その時のJSはあまり重要ではないかもしれません.検証や派手な効果をするだけです.2.関数を定義して、html元素のonXXX属性を与えます.
<script type="text/javascript">
function clk(){}
</script>
<div onclick="clk()">Div2 Element</div>
関数clkを先に定義して、Oclick属性に値を付けます.これも前世紀90年代の流行の書き方です.第一の方式より良いのは、業務論理コードを一つの関数にカプセル化して、HTMLコードとJSコードを少し分離させて、第一の種類ほど緊密に結合することはありません.3.element.onXXX方式を使う
<div id="d3">Div3 Element</div>
<script type="text/javascript">
var d3 = document.getElementById('d3');
d3.onclick = function(){ }
</script>
このような方式も初期の書き方であるが、JSとHTMLを完全に分離することができるというメリットがあり、HTML要素に追加のid属性(または他の要素オブジェクトを取得できるような方式)を提供する必要があるという前提がある.4.addEvent ListenerまたはatachEventを使用する
<div id="d4">Div4 Element</div>
<script type="text/javascript">
var d4 = document.getElementById('d4');
function clk(){alert(4)}
if(d4.addEventListener){
d4.addEventListener('click',clk,false);
}
if(d4.attachEvent){
d4.attachEvent('onclick',clk);
}
</script>
これは現在推奨されている方法で、前の2つの方法よりも機能が強く、要素に複数のイベントを追加することができます.イベントの泡が発生したり、捕獲されたりすることをサポートします.前の3つの方法はデフォルトでは泡が発生します.IE 6/7/8は依然として基準に従わずに独自のatachEventを使用しており、イベントキャプチャをサポートしていません.はい、方式4を簡単にパッケージして、標準ブラウザとIEブラウザに対応します.注意atachEventの最初のパラメータは「on」を追加する必要があります.addEvent Listenerの三つ目のパラメータはfalseであり、イベントの泡を表します.atachEventは第三のパラメータがありません.デフォルトでは泡が発生し、捕獲されません.
/**
*
* @param {Object} el HTML Element
* @param {Object} type
* @param {Object} fn handler
*/
function addEvent(el, type, fn){
if(el.addEventListener){
el.addEventListener(type, fn, false);
}else{
el.attachEvent('on' + type, fn);
}
}
はい、このツール関数を使ってdocumentにクリックイベントを追加します.function handler(){
alert(this);
alert(arguments[0]);
}
addEvent(document, 'click', handler);
Firefoxなどの標準ブラウザでは、ページをクリックすると「[object HTMLDocument]」が表示されます.また、handlerのthisはdocument自身です.しかし、IE 6/7/8では、thisはwindowオブジェクトです.これは人を不快にさせて、改正のもとで標準のブラウザーと統一します.function addEvent(el, type, fn){
if(el.addEventListener){
el.addEventListener(type, fn, false);
}else{
el['e' + fn] = function(){
fn.call(el, window.event);
}
el.attachEvent('on'+type, el['e'+fn]);
}
}
上に私達は一つのaddEventをカプセル化して、IE 6/7/8の下のイベントのhandlerの中でthisがwindowの誤りであることを解決して、そして事件の対象を統一しました.このページは対応する削除イベントの関数を追加します.前の篇の中でfnはIE 6/7/8の中で実際に包装されました.IE 6/7/8の中で本当のhandlerはel[e]+fnです.そのため削除する時に使うべきです.同時に二つの方法を一つのオブジェクトEにかけ、add、removeはそれぞれイベントを追加し、削除する.
E = {
//
add : function(el, type, fn){
if(el.addEventListener){
el.addEventListener(type, fn, false);
}else{
el['e'+fn] = function(){
fn.call(el,evt);
};
el.attachEvent('on' + type, el['e'+fn]);
}
},
//
remove : function(el, type, fn){
if(el.removeEventListener){
el.removeEventListener(type, fn, false);
}else if(el.detachEvent){
el.detachEvent('on' + type, el['e'+fn]);
}
}
};
IE 9/Firefox/Safari/Chrome/OperaはaddEventListener/removeveveveveveventListenerを使用してイベントを追加/削除しますが、IE 6/7/8はatachEvent/detachEventを使用します.標準ブラウザにおけるイベントhandlerは着信の三つ目のパラメータfnであり、IE 6/7/8は包装後のel[e]+fnである.イベントトリガー
はい、追加と削除の二つの方法があります.各ブラウザの下の部分的な違いを解決しました.アクティブトリガイベントを追加します.この方法は、クリック操作などのユーザの行動をシミュレートすることができる.標準はdispatch Event方法を使います.IE 6/7/8はfireEvent方法を使います.異常があるかもしれないので、try catchを使いました.
E = {
//
add : function(el, type, fn){
if(el.addEventListener){
el.addEventListener(type, fn, false);
}else{
el['e'+fn] = function(){
fn.call(el,window.event);
};
el.attachEvent('on' + type, el['e'+fn]);
}
},
//
remove : function(el, type, fn){
if(el.removeEventListener){
el.removeEventListener(type, fn, false);
}else if(el.detachEvent){
el.detachEvent('on' + type, el['e'+fn]);
}
},
//
dispatch : function(el ,type){
try{
if(el.dispatchEvent){
var evt = document.createEvent('Event');
evt.initEvent(type,true,true);
el.dispatchEvent(evt);
}else if(el.fireEvent){
el.fireEvent('on'+type);
}
}catch(e){};
}
};
これは事件モジュール全体の原形です.これからもっと完璧なところを補充する必要があります.しかし、これらの関数は普通の応用には十分適任です.完全である
上のaddに問題があります.同じタイプのイベントに複数のhanderを追加すると、IE 6/7/8の下で無秩序になります.
<div id="d1" style="width:200px;height:200px;background:gold;"></div>
<script type="text/javascript">
var el = document.getElementById('d1');
function handler1(){alert('1');}
function handler2(){alert('2');}
function handler3(){alert('3');}
function handler4(){alert('4');}
function handler5(){alert('5');}
E.add(el, 'click', handler1);
E.add(el, 'click', handler2);
E.add(el, 'click', handler3);
E.add(el, 'click', handler4);
E.add(el, 'click', handler5);
</script>
IE 9/Firefox/Safari/Chomre/Operaは1,2,3,4,5を順次出力します.ただし、IE 6/7/8では必ずしもそうではない.すべてのブラウザの中の複数のイベントを解決するために、handlerが規則的に実行するために、すべてのhandlerを管理するための待ち行列が必要です.今回は、すべての内部詳細を匿名関数にカプセル化し、この関数を実行した後、上記のインターフェースと同じ方法に戻ります.また
E = function(){
function _isEmptyObj(obj){
for(var a in obj){
return false;
}
return true;
}
function _each(ary, callback){
for(var i=0,len=ary.length; i<len;){
callback(i, ary[i]) ? i=0 : i++;
}
}
function _remove(el, type){
var handler = el.listeners[type]['_handler_'];
el.removeEventListener ?
el.removeEventListener(type, handler, false) :
el.detachEvent('on'+type, handler);
delete el.listeners[type];
if(_isEmptyObj(el.listeners)){
delete el.listeners;
}
}
//
function add(el, type, fn){
el.listeners = el.listeners || {};
var listeners = el.listeners[type] = el.listeners[type] || [];
listeners.push(fn);
if(!listeners['_handler_']){
listeners['_handler_'] = function(e){
var evt = e || window.event;
for(var i=0,fn; fn=listeners[i++];){
fn.call(el, evt);
}
}
el.addEventListener ?
el.addEventListener(type, listeners['_handler_'], false) :
el.attachEvent('on' + type, listeners['_handler_']);
}
}
//
function remove(el, type, fn){
if(!el.listeners) return;
var listeners = el.listeners && el.listeners[type];
if(listeners) {
_each(listeners, function(i, f){
if(f==fn){
return listeners.splice(i, 1);
}
});
if(listeners.length == 0){
_remove(el,type);
}
}
}
//
function dispatch(el ,type){
try{
if(el.dispatchEvent){
var evt = document.createEvent('Event');
evt.initEvent(type,true,true);
el.dispatchEvent(evt);
}else if(el.fireEvent){
el.fireEvent('on'+type);
}
}catch(e){};
}
return {
add: add,
remove: remove,
dispatch: dispatch
};
}();
上でIE 6/7/8の同じタイプのイベントを解決した複数のhandlerが無秩序に実行している場合、そのための変更も大きいです.実現は前のバージョンとはほとんど違います.しかし、メリットも明らかです.一回だけ実行するイベントを追加する必要がある場合があります.このために、add方法に第4のパラメータoneを追加します.oneはtrueであると、このイベントはhandlerに一回だけ実行されます.
<div id="d1" style="width:200px;height:200px;background:gold;"></div>
<script>
var el = document.getElementById('d1');
function handler(){alert(5)}
E.add(el, 'click', handler, true);
</script>
remove関数を拡張します.function handler1(){alert('1');}
function handler2(){alert('2');}
function handler3(){alert('3');}
function handler4(){alert('4');}
E.add(el, 'click', f1);
E.add(el, 'click', f2);
E.add(el, 'click', f3);
E.add(el, 'mouseover', f4);
以下の文を使って、要素clickのすべてのhandler:E.remove(el,'click')を削除します.以下は元素にあるすべてのイベントを削除します.clickとmouseoverを含みます.E.remove(el).
上に正式に私のイベントモジュールイベントがあります.v 1は、最初のフレームを組み立てられています.多くのJSライブラリや枠組みに比べて、まだ事件の対象となる互換性がないという人もいるかもしれません.はい、わざとこれを後から補充します.事件の対象の互換性の問題が多すぎて、ややこしいです.
次に私は私有の_を導入します.fixEvent関数、addではこの関数を呼び出します._fixEventは元のイベントオブジェクトを修復し、標準的な統一インターフェースのイベントオブジェクトを返します.次のとおりです
function _fixEvent( evt, el ) {
var props = "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
len = props.length;
function now() {return (new Date).getTime();}
function returnFalse() {return false;}
function returnTrue() {return true;}
function Event( src ) {
this.originalEvent = src;
this.type = src.type;
this.timeStamp = now();
}
Event.prototype = {
preventDefault: function() {
this.isDefaultPrevented = returnTrue;
var e = this.originalEvent;
if( e.preventDefault ) {
e.preventDefault();
}
e.returnValue = false;
},
stopPropagation: function() {
this.isPropagationStopped = returnTrue;
var e = this.originalEvent;
if( e.stopPropagation ) {
e.stopPropagation();
}
e.cancelBubble = true;
},
stopImmediatePropagation: function() {
this.isImmediatePropagationStopped = returnTrue;
this.stopPropagation();
},
isDefaultPrevented: returnFalse,
isPropagationStopped: returnFalse,
isImmediatePropagationStopped: returnFalse
};
var originalEvent = evt;
evt = new Event( originalEvent );
for(var i = len, prop; i;) {
prop = props[ --i ];
evt[ prop ] = originalEvent[ prop ];
}
if(!evt.target) {
evt.target = evt.srcElement || document;
}
if( evt.target.nodeType === 3 ) {
evt.target = evt.target.parentNode;
}
if( !evt.relatedTarget && evt.fromElement ) {
evt.relatedTarget = evt.fromElement === evt.target ? evt.toElement : evt.fromElement;
}
if( evt.pageX == null && evt.clientX != null ) {
var doc = document.documentElement, body = document.body;
evt.pageX = evt.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);
evt.pageY = evt.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0);
}
if( !evt.which && ((evt.charCode || evt.charCode === 0) ? evt.charCode : evt.keyCode) ) {
evt.which = evt.charCode || evt.keyCode;
}
if( !evt.metaKey && evt.ctrlKey ) {
evt.metaKey = evt.ctrlKey;
}
if( !evt.which && evt.button !== undefined ) {
evt.which = (evt.button & 1 ? 1 : ( evt.button & 2 ? 3 : ( evt.button & 4 ? 2 : 0 ) ));
}
if(!evt.currentTarget) evt.currentTarget = el;
return evt;
}
はい、今はあなたがほしいです.