5

私は、クロスブラウザーのイベント処理システムに取り組んでいました。そして、何人かの開発者にコードのレビューを依頼しました。開発者の 1 人は、私の実装は実際のイベントではなく、コールバックに基づいていると言っていました。違いはなんですか?

便宜上 (およびgist としても)、実装のソース コードを以下に示します。これまでのところ、問題は見つかりませんでした。テストしたすべてのブラウザで問題なく動作します。

問題の説明が悪くて申し訳ありません。私はその純粋なイベントの部分に慣れていません。

var evento = (function (window) {
  var win = window
    , doc = win.document
    , _handlers = {}
    , addEvent
    , removeEvent
    , triggerEvent;

  addEvent = (function () {
    if (typeof doc.addEventListener === "function") {
      return function (el, evt, fn) {
        el.addEventListener(evt, fn, false);
        _handlers[el] = _handlers[el] || {};
        _handlers[el][evt] = _handlers[el][evt] || [];
        _handlers[el][evt].push(fn);

      };
    } else if (typeof doc.attachEvent === "function") {
      return function (el, evt, fn) {
        el.attachEvent(evt, fn);
        _handlers[el] = _handlers[el] || {};
        _handlers[el][evt] = _handlers[el][evt] || [];
        _handlers[el][evt].push(fn);
      };
    } else {
      return function (el, evt, fn) {
        el["on" + evt] = fn;
        _handlers[el] = _handlers[el] || {};
        _handlers[el][evt] = _handlers[el][evt] || [];
        _handlers[el][evt].push(fn);
      };
    }
  }());

  // removeEvent
  removeEvent = (function () {
    if (typeof doc.removeEventListener === "function") {
      return function (el, evt, fn) {
        el.removeEventListener(evt, fn, false);
        Helio.each(_handlers[el][evt], function (fun) {
          if (fun === fn) {
            _handlers[el] = _handlers[el] || {};
            _handlers[el][evt] = _handlers[el][evt] || [];
            _handlers[el][evt][_handlers[el][evt].indexOf(fun)] = undefined;
          }
        });

      };
    } else if (typeof doc.detachEvent === "function") {
      return function (el, evt, fn) {
        el.detachEvent(evt, fn);
        Helio.each(_handlers[el][evt], function (fun) {
          if (fun === fn) {
            _handlers[el] = _handlers[el] || {};
            _handlers[el][evt] = _handlers[el][evt] || [];
            _handlers[el][evt][_handlers[el][evt].indexOf(fun)] = undefined;
          }
        });
      };
    } else {
      return function (el, evt, fn) {
        el["on" + evt] = undefined;
        Helio.each(_handlers[el][evt], function (fun) {
          if (fun === fn) {
            _handlers[el] = _handlers[el] || {};
            _handlers[el][evt] = _handlers[el][evt] || [];
            _handlers[el][evt][_handlers[el][evt].indexOf(fun)] = undefined;
          }
        });
      };
    }
  }());

  // triggerEvent
  triggerEvent = function (el, evt) {
    _handlers[el] = _handlers[el] || {};
    _handlers[el][evt] = _handlers[el][evt] || [];

    for (var _i = 0, _l = _handlers[el][evt].length; _i < _l; _i += 1) {
      _handlers[el][evt][_i]();
    }
  };

  return {
    add: addEvent,
    remove: removeEvent,
    trigger: triggerEvent,
    _handlers: _handlers
  };
}(this));
4

1 に答える 1

2

あなたのシステムがコールバック、イベント、またはラムダ計算に基づいていることはあまり気にしませんでした。あなたがここで公開しているビットについては、かなりよく書かれているように見え、良い仕事をすることを約束します (ただし、あなたがどのように処理したかについては興味がありますremoveEvent();))。

ただし、実装についていくつかのコメントがあります。

  • イベント ハンドラーを追加するたびに、実行するブラウザーを確認する必要はありません。

プロパティを呼び出すたびに、プロパティの存在を確認する慣行を受け入れている人の数に驚かされます。関数呼び出しの途中で IE を FF に交換する人はいません (そしてdocument.addEventListener、実際の ECMA-5 置換以外のプロパティを定義するほど愚かな人は、私に言わせれば、むち打ちで死ぬに値します)。次のように、最初からオンにして、それで完了します。

if (doc.addEventListener) {
    addEvent  = // ...
    freeEvent = // ...
}
else if (doc.attachEvent) {
    addEvent  =  // ...
    freeEvent =  // ...
}
/* etc. */
  • ハンドラーをアタッチするための統一されたインターフェイスを提供しますが、コードを実行するブラウザーによっては、実際のハンドラーの動作が異なります。

たとえば、IE8 では、イベントのターゲットは ECMA-5 規則と同じ方法では利用できません。

実際のクロスブラウザー インターフェイスを提供したい場合は、統一された実行コンテキストをイベント ハンドラーに提供する必要があります。これには、次のような「キャンセル」機能が含まれる場合があります。

cancel = function (e) { e.returnValue = false; }; // IE8-
cancel = function (e) { e.preventDefault();    }; // ECMA-5

thisまた、IE8 の下でターゲット オブジェクトに復元し、セマンティクスとを統一する必要targetがありevent.targetます。

本当にプログラマーに優しくしたいのなら、次のような奇妙なことに取り組むこともできます。

  • IE8 でロード イベントが発生しない - 画像が既にキャッシュされている場合
  • 途方もなく複雑なマウス ホイール レポート システム

おそらく他にもいくつかあります。

私自身の目的のために行った方法は、実際のハンドラーの周りにラッパーを生成することでした。これにより、すべてのプラットフォームの特性を処理し、実際のユーザー コードを呼び出す前に一貫した実行コンテキストを確立できます。

最後のコメント: その美しさを除けば、Netscape4 スタイルのイベントをサポートする必要があるかどうかはよくわかりません。でもそれは信仰の問題なので...

于 2013-12-30T01:05:27.923 に答える