2012-06-11 28 views
9

我想要的是提供一些事件的自定義對象。 例如:在我自己的對象中實現事件

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使用事件的默認方式。 但我不能讓它成爲...

目前我的問題是,我的對象沒有實現「addEventListener」和「dispatchEvent」。但是這個功能通常是從「元素」實現的...

我可以讓它們以某種方式提供嗎?還是我必須爲我自己實現它們? 我該如何執行它們? 我是否必須實現自己的事件處理? (具有處理程序的內部列表,「添加」和「刪除」處理程序功能,並且當我想要觸發事件時觸發每個處理程序)

問候!

+0

我不;噸知道這是否幫助,但Backbone.js的具有內置到他們的活動。使用它創建的每個模型都可以使用語法'object.trigger(event_name)'觸發自定義事件' – Deeptechtons

+0

使用jQuery也很容易...這就是爲什麼我不能很難:P $(_ this).trigger(CustomObjectTextChangedEventName ,_text); $(myCustomObject).bind(CustomObjectTextChangedEventName,handleTextChanged); –

回答

15

addEventListener功能是Element類的一種方法。一種方法是使CustomObject繼承Element這樣的:

CustomObject.prototype = Element.prototype; 

的問題是,Element類可能有不同的瀏覽器之間不同的實現。因此,舉個例子,射擊事件可能並不容易(見this post)。

所以我建議你自己做這個。這就不難,嘗試這樣的事情:

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']); 

這是一個基本的解決方案。你可能想改變它,但我認爲你應該掌握這個想法。

+0

這就是我所擁有的「有一個內部的處理程序列表,一個」添加「和」刪除「處理函數,並且當我想要觸發事件時觸發每個處理程序」=)謝謝! –

+0

@DominikKirschenhofer酷。我忘記了'remove'處理程序,所以我剛添加它。它應該工作。 :) – freakish

+1

關於「棘手」部分 - 通過傳遞相同的函數對象來移除處理程序:原生事件處理程序也是如此。我只測試了按鈕'click'事件,'removeEventListener'不起作用,除非我提供了對同一個函數對象的引用。 – GolfWolf

1

我不知道所有的100%,但接下來的是我這個問題中的老研究的結果:

  • 您不能提供莫名其妙這一點。
  • 你可以簡單地實現自己的邏輯。爲此,您可以使用MDN element.removeEventListener文章中存在的代碼,但只需稍作更改。下面把它複製的代碼\過去從MDN鏈接:

// 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); } 
    } 
    }; 
} 
  • 我想你需要改變的是與CustomObject.prototype更換Element.prototype。並且爲了支持dispathEvent,您必須添加CustomObject.prototype.dispatchEvent = runListener;代碼行。也可以將此代碼封裝到關閉函數中更好;

我沒有在我的應用程序中測試過,但也許這可以幫助你。

UPDATE: 接着鏈接點到包含XObject()類支持事件添加/移除和分派事件的代碼源。包括測試示例。所有的代碼都基於上面的答案。 http://jsfiddle.net/8jZrR/

+0

@Dominik Kirschenhofer,請參閱鏈接**更新:**段落 –

+0

COOL!謝謝! –

1

我改進了我的示例,代碼來自怪異。我仍然會提取事件處理部分到「基類」...也許當有更多的時間=)

還有一個使用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 = document.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>