互換性の問題はクラス ライブラリを使用すると簡単に解決できますが、そのメカニズムについて少しずつ説明していきます。
まず、DOM Level2 はイベント処理用の 2 つの関数
addEventListener と removeEventListener を定義します。どちらも EventTarget インターフェースからのものです。 🎜>
コードをコピーします
コードは次のとおりです。 element.addEventListener(eventName,listener,useCapture); >element .removeEventListener(eventName,listener,useCapture);
EventTarget インターフェイスは通常、Node または Window インターフェイスから実装されます。
たとえば、次のようになります。
コードをコピー
コードは次のとおりです: 関数loadHandler() { console.log ('ページが読み込まれました!')
}
window.addEventListener('load',loadHandler, false);
削除中リスナーは、removeEventListener を使用して簡単に実行できます。削除されたハンドルと追加されたハンドルが関数を参照していることに注意してください。
完璧な世界では、関数はここで終了します。
しかし、IE は独自の 2 つの関数attachEvent と detachEvent が定義されており、addEventListener とremoveEventListener を置き換えます。
そのため、実際に行う必要があるのは、IE ブラウザと w3c 標準間のイベント処理の違いに対処することです。
モニタリングを追加し、リスナーを削除するには、次のように記述します。
コードをコピー
window.detachEvent ('onload',loadHandler); // モニタリングを削除します
表面から、IE と w3c の間に 2 つの違いがあることがわかります。
1 の前に「on」プレフィックスがあります。
2. useCapture の 3 番目のパラメーターは削除されました。
実際には、これら 2 つの違いについてはさらに分析していきます。共通関数
コードをコピー
else if (element.attachEvent) {
element.attachEvent( 'on' イベント名, ハンドラー);
}
else {
element['on' イベント名] = ハンドラー;
}
}
関数 RemoveListener(要素, イベント名, ハンドラー) {
if (element.addEventListener) {
element.removeEventListener(eventName, handler, false);
}
else if (element.detachEvent) {
element.detachEvent('on'
}
else {
element['on'eventName] = null;
注意すべき点が 2 つあります。上記の関数について:
1. まず、IE が徐々に標準に近づいているため、最初にこのブランチの w3c 標準を測定するのが最善です。
2.
パフォーマンスの最適化
上記の関数では、各バインディング イベントにはブランチが必要です。
このように、事前に検出するために「実行前」に変更する必要があります。 document.body を使用しない理由は、ドキュメントの準備ができていないときに document.body がすでに存在しているためです。
このように、関数は
コードをコピー
コードは次のとおりです:
var addListener, RemoveListener,
/* テスト要素 */
docEl = document.documentElement;
// addListener
if (docEl.addEventListener) {
/* `addEventListener` がテスト要素に存在する場合、`addEventListener` を使用する関数を定義 */
addListener = function (element,eventName, handler) {
element.addEventListener(eventName, handler, false);
};
}
else if (docEl.attachEvent) {
/* `attachEvent` がテスト要素に存在する場合、`attachEvent` を使用する関数を定義 */
addListener = function (要素, イベント名, ハンドラー) {
element.attachEvent('on' イベント名, ハンドラー);
};
}
else {
/* どちらのメソッドもテスト要素に存在しない場合は、フォールバック戦略に関数を定義します */
addListener = function (element,eventName,handler) {
element['on ' イベント名] = ハンドラー;
};
}
//removeListener
if (docEl.removeEventListener) {
removeListener = function (element,eventName, handler) {
element.removeEventListener(eventName, handler, false);
};
}
else if (docEl.detachEvent) {
removeListener = function (要素, イベント名, ハンドラー) {
要素.detachEvent('on' イベント名, ハンドラー);
};
}
else {
removeListener = function (要素, イベント名, ハンドラー) {
要素['on' イベント名] = null;
};
}
これは回避済每次绑定都判断が必要です。
上の利点は、これにも 2 つのハードコードがあります。 代コード量の増加を除いて、ある点はハードウェア推测を使用していることです。これは安全ではありません。
不安全な检测
下の二つの例文説明。ある状況下ではこれは十分安全ではありません。
// Internet Explorer の場合
var xhr = new ActiveXObject('Microsoft.XMLHTTP');
if (xhr.open) { } // エラー
var element = document.createElement('p');
if (element.offsetParent) { } // エラー
例: IE7 下の typeof xhr.open === 'unknown'。 详细参考feature-detection
所以我们提倡の检测方式は
var isHostMethod = function (オブジェクト, メソッド名) {
var t = オブジェクトの種類[メソッド名];
return ((t === '関数' || t === 'オブジェクト') && !!オブジェクト[メソッド名]) || t === '不明';
};
この样我们上の优化関数。再次改进成この样
var addListener, docEl = document.documentElement;
if (isHostMethod(docEl, 'addEventListener')) {
/* ... */
}
else if (isHostMethod(docEl, 'attachEvent')) {
/* ... */
}
else {
/* ... */
}
失われたこの指针
この指针の处理.IE w3c との違いは、w3c の関数の指示は、その句柄を決定する DOM 要素を指示することです。 而IE下破总はウィンドウを指します。
// IE
document.body.attachEvent( 'onclick', function () {
alert(this === window) // true
alert(this === document.body) // false
});
// W3C
document.body.addEventListener('onclick', function () {
alert(this === window); // false
alert(this === document.body) ); // true
});
这个问题修正起来也不算麻烦
if (isHostMethod(docEl, 'addEventListener')) {
/* ... */
}
else if (isHostMethod(docEl, 'attachEvent')) {
addListener = function (element, イベント名, handler) {
element.attachEvent('on' イベント名, function () {
handler.call(element, window.event);
});
};
}
else {
/* ... */
}
その後、呼び出しを使用してハンドラーのポインターを内部的に修正するだけです。実際、ここで密かに修正された問題があることに誰もが気づいているはずです。は最初の関数を通過せず、グローバルな世界に残されます。そのため、ここでも次のような大きな問題を修正しました。しばらく停止して簡単なテストを行うことができます。
1. ブラウザー間の互換性 2. このポインターが指す互換性
テストコードは次のとおりです: