Реализация событий в моем собственном объекте

То, что я хочу иметь, это пользовательский объект, который обеспечивает некоторые события. Например:

var CustomObjectTextChangedEventName = 'textChanged';
var CustomObject = function () {
    var _this = this;
    var _text = "";

    _this.OnTextChanged = document.createEvent("Event");
    _this.OnTextChanged.initEvent(CustomObjectTextChangedEventName, true, false);

    _this.ChangeText = function (newText) {
        _text = newText;
        fireTextChanged();
    };

    function fireTextChanged() {
        _this.dispatchEvent(_this.OnTextChanged);
    }
}

Код для использования события будет выглядеть так:

myCustomObject = new CustomObject();
myCustomObject.addEventListener(CustomObjectTextChangedEventName, handleTextChanged, false);

Как видите ... способ использования событий в JS по умолчанию. Но я не могу сделать это беспокойным ...

В настоящее время моя проблема заключается в том, что мой объект не реализует & quot; addEventListener & quot; и "dispatchEvent". Но эти функции обычно реализуются из "элемента" ...

Могу ли я сделать их доступными каким-либо образом или я должен реализовать их самостоятельно? Как мне их реализовать? Должен ли я реализовать свою собственную обработку событий? (наличие внутреннего списка обработчиков, функции «добавить» - и «удалить» и запускать каждый обработчик, когда я хочу запустить событие)

Привет!

 Dominik Kirschenhofer11 июн. 2012 г., 13:50
Это также просто с jQuery ... вот почему я подумал, что это не так сложно: P $ (_ this) .trigger (CustomObjectTextChangedEventName, _text); $ (myCustomObject) .bind (CustomObjectTextChangedEventName, handleTextChanged);
 Deeptechtons11 июн. 2012 г., 13:37
Я не знаю, помогает ли это, но в Backbone.js есть встроенные события. Каждая модель, созданная с ее помощью, может вызывать пользовательские события, используя синтаксисobject.trigger(event_name)

Ответы на вопрос(4)

но следующее - результат моего старого исследования этой проблемы:

You cannot make available somehow this. You can simply implement your own logic. For this you can use code that exist in MDN element.removeEventListener article with little changes. Below it copy\past of code from MDN link:
// code source: MDN: https://developer.mozilla.org/en/DOM/element.removeEventListener
// without changes
if (!Element.prototype.addEventListener) {  
  var oListeners = {};  
  function runListeners(oEvent) {  
    if (!oEvent) { oEvent = window.event; }  
    for (var iLstId = 0, iElId = 0, oEvtListeners = oListeners[oEvent.type]; iElId < oEvtListeners.aEls.length; iElId++) {  
      if (oEvtListeners.aEls[iElId] === this) {  
        for (iLstId; iLstId < oEvtListeners.aEvts[iElId].length; iLstId++) { oEvtListeners.aEvts[iElId][iLstId].call(this, oEvent); }  
        break;  
      }  
    }  
  }  
  Element.prototype.addEventListener = function (sEventType, fListener /*, useCapture (will be ignored!) */) {  
    if (oListeners.hasOwnProperty(sEventType)) {  
      var oEvtListeners = oListeners[sEventType];  
      for (var nElIdx = -1, iElId = 0; iElId < oEvtListeners.aEls.length; iElId++) {  
        if (oEvtListeners.aEls[iElId] === this) { nElIdx = iElId; break; }  
      }  
      if (nElIdx === -1) {  
        oEvtListeners.aEls.push(this);  
        oEvtListeners.aEvts.push([fListener]);  
        this["on" + sEventType] = runListeners;  
      } else {  
        var aElListeners = oEvtListeners.aEvts[nElIdx];  
        if (this["on" + sEventType] !== runListeners) {  
          aElListeners.splice(0);  
          this["on" + sEventType] = runListeners;  
        }  
        for (var iLstId = 0; iLstId < aElListeners.length; iLstId++) {  
          if (aElListeners[iLstId] === fListener) { return; }  
        }       
        aElListeners.push(fListener);  
      }  
    } else {  
      oListeners[sEventType] = { aEls: [this], aEvts: [ [fListener] ] };  
      this["on" + sEventType] = runListeners;  
    }  
  };  
  Element.prototype.removeEventListener = function (sEventType, fListener /*, useCapture (will be ignored!) */) {  
    if (!oListeners.hasOwnProperty(sEventType)) { return; }  
    var oEvtListeners = oListeners[sEventType];  
    for (var nElIdx = -1, iElId = 0; iElId < oEvtListeners.aEls.length; iElId++) {  
      if (oEvtListeners.aEls[iElId] === this) { nElIdx = iElId; break; }  
    }  
    if (nElIdx === -1) { return; }  
    for (var iLstId = 0, aElListeners = oEvtListeners.aEvts[nElIdx]; iLstId < aElListeners.length; iLstId++) {  
      if (aElListeners[iLstId] === fListener) { aElListeners.splice(iLstId, 1); }  
    }  
  };  
}  
I think what all you need to change is to replace Element.prototype with CustomObject.prototype. And for supporting dispathEvent you must add CustomObject.prototype.dispatchEvent = runListener; code line. Also is can be better to enclose this code into closure function;

Я не проверял это в своих приложениях, но, возможно, это поможет вам.

UPDATE: Следующая ссылка указывает на источник кода, который содержитXObject() класс, который поддерживает добавление / удаление и диспетчеризацию событий. Тестовый пример включен. Весь код основан на ответе выше. http://jsfiddle.net/8jZrR/

 11 июн. 2012 г., 14:26
@Dominik Kirschenhofer, см. Ссылку вUPDATE: параграф
 Dominik Kirschenhofer11 июн. 2012 г., 15:12
ПРОХЛАДНО! Спасибо!

jsfiddle

Это наивный подход, но он может работать для некоторых приложений:

CustomEventTarget.prototype = {

    'constructor': CustomEventTarget,

    on:   function( ev, el ) { this.eventTarget.addEventListener( ev, el ) },
    off:  function( ev, el ) { this.eventTarget.removeEventListener( ev, el ) },
    emit: function( ev ) { this.eventTarget.dispatchEvent( ev ) }

}

function CustomEventTarget() { this.eventTarget = new EventTarget }
Решение Вопроса

addEventListener функция является методомElement учебный класс. Один из способов сделатьCustomObject наследовать отElement как это:

Проблема в том, чтоElement Класс может иметь разные реализации среди разных браузеров. Так, например, события стрельбы могут быть нелегкими (см.эта почта).

Поэтому я советую делать это самостоятельно. Это не сложно, попробуйте что-то вроде этого:

var CustomObject = function () {
    var _this = this;
    _this.events = {};

    _this.addEventListener = function(name, handler) {
        if (_this.events.hasOwnProperty(name))
            _this.events[name].push(handler);
        else
            _this.events[name] = [handler];
    };

    _this.removeEventListener = function(name, handler) {
        /* This is a bit tricky, because how would you identify functions?
           This simple solution should work if you pass THE SAME handler. */
        if (!_this.events.hasOwnProperty(name))
            return;

        var index = _this.events[name].indexOf(handler);
        if (index != -1)
            _this.events[name].splice(index, 1);
    };

    _this.fireEvent = function(name, args) {
        if (!_this.events.hasOwnProperty(name))
            return;

        if (!args || !args.length)
            args = [];

        var evs = _this.events[name], l = evs.length;
        for (var i = 0; i < l; i++) {
            evs[i].apply(null, args);
        }
    };
}

Теперь использовать его так же просто, как:

var co = new CustomObject();
co.addEventListener('textChange', function(name) {
    console.log(name); 
});
co.fireEvent('textChange', ['test']);

Это базовое решение. Вы можете изменить это, но я думаю, что вы должны понять идею.

 04 сент. 2017 г., 04:44
Причудливый, почему ты использовалvar _this = this в начале?
 11 июн. 2012 г., 13:53
@DominikKirschenhofer Круто. Я забыл оremove обработчик, поэтому я только что добавил его. Он должен работать. :)
 Dominik Kirschenhofer11 июн. 2012 г., 13:38
Это то, что я имею в виду, имея «внутренний список обработчиков, функцию« добавить »- и« удалить »- обработчик и запускать каждый обработчик, когда я хочу вызвать событие»; =) Спасибо!
 04 сент. 2017 г., 04:46
О, НВМ, потому что вы хотели использовать его в дочерних функциях, гдеthis был бы повторно объявлен.
 24 мая 2015 г., 20:44
Относительно "хитрого" частичное удаление обработчиков путем передачи одного и того же функционального объекта: то же самое верно для собственных обработчиков событий Я только что проверил кнопкиclick событие иremoveEventListener не работал, если я не предоставил ссылку на тот же объект функции.

часть обработки событий в «базовый класс» ... возможно, когда есть еще время =)

Также есть пример использования jQuery!

<!doctype html>
<html lang="en">
<head>    
    <title>Custom Events Test</title>    
    <meta charset="utf-8">    
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>    
    <script>
        /* jQuery

        var CustomObjectTextChangedEventName = 'textChanged';
        var CustomObject = function () {
            var _this = this;
            var _text = "";

            _this.ChangeText = function (newText) {
                _text = newText;
                fireTextChanged();
            };

            function fireTextChanged() {
                $(_this).trigger(CustomObjectTextChangedEventName, _text);
            }
        }

        var myCustomObject;
        $(document).ready(function () {
            myCustomObject = new CustomObject();
            $(myCustomObject).bind(CustomObjectTextChangedEventName, handleTextChanged);
        })

        function handleTextChanged(event, msg) {
            window.alert(msg);
        }

        function buttonClick() {
            var newText = document.getElementById('tbText').value;

            myCustomObject.ChangeText(newText);
        }

        */


        var CustomObjectTextChangedEventName = 'textChanged';
        var CustomObject = function (alias) {
            var _this = this;
            var _events = {};
            var _text = "";

            _this.Alias = alias;

            _this.OnTextChanged = document.createEvent("Event");
            _this.OnTextChanged.initEvent(CustomObjectTextChangedEventName, true, false);

            _this.ChangeText = function (newText) {
                var args = new TextChangedEventArgs();
                args.OldText = _text;
                args.NewText = newText;

                _text = newText;
                fireEvent(CustomObjectTextChangedEventName, args);
            };

            _this.addEventListener = function (name, handler) {
                if (_events.hasOwnProperty(name))
                    _events[name].push(handler);
                else
                    _events[name] = [handler];
            };

            _this.removeEventListener = function (name, handler) {
                /* This is a bit tricky, because how would you identify functions? 
                This simple solution should work if you pass THE SAME handler. */
                if (!_events.hasOwnProperty(name))
                    return;

                var index = _events[name].indexOf(handler);
                if (index != -1)
                    _events[name].splice(index, 1);
            };

            function fireEvent(name, args) {
                if (!_events.hasOwnProperty(name))
                    return;

                var evs = _events[name], l = evs.length;
                for (var i = 0; i < l; i++) {
                    evs[i](_this, args);
                }
            }
        }

        var TextChangedEventArgs = function () {
            var _this = this;

            _this.OldText = null;
            _this.NewText = null;
        }

        var myCustomObject;
        var myCustomObject2;
        window.onload = function () {
            myCustomObject = new CustomObject("myCustomObject");
            myCustomObject.addEventListener(CustomObjectTextChangedEventName, handleTextChanged);

            myCustomObject2 = new CustomObject("myCustomObject2");
            myCustomObject2.addEventListener(CustomObjectTextChangedEventName, handleTextChanged);
        };

        function handleTextChanged(sender, args) {
            window.alert('At ' + sender.Alias + ' from [' + args.OldText + '] to [' + args.NewText + ']');
        }

        function buttonClick() {
            var newText = doc,ument.getElementById('tbText').value;

            myCustomObject.ChangeText(newText);
        }

        function buttonClick2() {
            var newText = document.getElementById('tbText2').value;

            myCustomObject2.ChangeText(newText);
        }
    </script>
</head>
<body>
    <input type="text" id="tbText" />
    <input type="button" value="Change" onclick="buttonClick();" />

    <input type="text" id="tbText2" />
    <input type="button" value="Change" onclick="buttonClick2();" />
</body>

Ваш ответ на вопрос