将对象上的事件路由到另一个对象

时间:2009-09-19 02:55:53

标签: javascript jquery events

我希望将目标origTarget上发生的所有事件路由/重定向到另一个对象otherObject。我想完成这样的事情:

/* Magic binding (doesn't work!). */
$(origTarget).bind('*', function(e) {
    $(otherObject).trigger(e);
});

这是否可以使用jQuery而无需遍历每个可能的事件类型?

此示例应以'hello'警告:

var origTarget = { };
var otherObject = { };

/* Do magic binding here. */

$(otherObject).bind('alert', function() {
    alert('hello');
});

$(origTarget).trigger('alert');

1 个答案:

答案 0 :(得分:6)

我认为您所寻找的内容可以通过重新评估您如何绑定您的活动来实现。如果你真的想看看目标对象中发生了什么,你应该将事件绑定到目标对象。

话虽如此,让我们试着找到一个解决方案

进入jQuery.event的东西,我看不到任何“简单的方法”来实现这一目标。但是,似乎事件使用jQuery.data(elem,'events')缓存在对象中。您可以选择探索

将绑定事件从一个对象复制到另一个对象

在jQuery 1.3.2中编写和测试的潜在事件复制解决方案:

(function($){ 
  $.fn.proxyEventsFrom = function(target) {
    // cache this for later
    var $target = $(target);

    return this.each(function() {
      // store a copy of the element to use in the event handler callback
      var elem = this; 

      // get a list of events that I subscribe to
      var events = $(this).data("events") || {};

      $.each(events, function(type, handlers) {
        // bind onto this event on the target
        $target.bind(type, function(event) {
          var evArgs = arguments;
          // store the element that event originally fired on in the event object.
          event.proxyFrom = this; 
          $.each(handlers, function(guid, handler) {
            var ret = handler.apply(elem, evArgs);
            // to behave like other event handlers.
            if( ret !== undefined ){
              event.result = ret;
              if ( ret === false ) {
                event.preventDefault();
                event.stopPropagation();
                return false; // stop our each loop too
              }
            }
          }); // end $.each(handlers, function(guid, handler) 
          return event.result;
        }); // end $target.bind(type, function(event) 
      });// end $.each(events, function(type, handlers) 
    });// end this.each(function() {});
  }; // end $.fn.proxyEventsFrom
})(jQuery);

$(someObject).proxyEventsFrom(targetObject);

这可以通过阅读someObject正在侦听的所有事件,然后在同一事件类型的targetObject上绑定一个新事件来调用{{1}上的所有事件处理程序}}。 someObject上的事件处理程序可能如下所示:

someObject

如果您将事件代理到代理回来的事件,则此方法可以轻松生成事件处理程序的递归循环。小心。

覆盖$(someObject).bind('alert', function(e) { if (e.proxyFrom) { alert('Proxied Succesfully!'); } alert('test'); }); $(someObject).proxyEventsFrom(targetObject); $(targetObject).trigger('alert');

可以覆盖事件触发功能来完成你想要的事情,虽然我建议反对它有几个原因:覆盖图书馆中的东西是危险的,你最终会得到比你想要的更多的东西,此函数只会被jQuery.event.trigger显式调用 - 因此不适用于标准DOM事件。

.trigger()

使目标的事件===另一个对象的事件

如果origTarget没有自己绑定的事件,您可以通过引用复制事件对象。

  (function() { // wrap this in a closure so origTrigger can't be overwritten.
    var origTrigger = jQuery.event.trigger;
    jQuery.event.trigger = function(event, data, elem, bubbling)
    {
      if (elem === origTarget) {
        if (origTrigger.call(this, event, data, otherObject, bubbling) === false) return;
      } 
      return origTrigger.apply(this,arguments);
    }
  })();

自定义'句柄'功能

这个解决方案还有很长的路要走,内部所有jQuery事件都通过存储在 // copy the events table by reference from otherObject "events" data // (create if neccesary) $.data(origTarget, 'events', $.data(otherObject,'events') || $.data(otherObject,'events',{})); // need to setup handler since jQuery isn't creating it for us // function source found on line 2465 of jquery-1.3.2.js var handle = $.data(origTarget, 'handle', function(){ return typeof jQuery !== "undefined" && !jQuery.event.triggered ? jQuery.event.handle.apply(arguments.callee.elem, arguments) : undefined; }); handle.elem = origTarget; 中的'handle'函数传递。因此,如果您在目标上覆盖该函数,则应该能够将事件代理到另一个对象。这个解决方案假设你只有一个额外的监听器,它可以很容易地适应多个监听器。我认为这是我提出的最佳方法:

$.data(elem, 'handle')

它甚至适用于DOM Elements(尽管你需要传递元素,而不是jQuery对象)

  jQuery.event.proxyEvents = function(fromObject, toObject) {
    // create an new handle function
    var newHandle = function(event) {
      // the test in the original handler returns undefined if jQuery.event.triggered
      if (jQuery.event.triggered) return undefined;
      // event should be safe - but just in case lets take a trick from
      // jQuery.event.handle
      event = arguments[0] = jQuery.event.fix(event || window.event);
      // if we have a "listener"
      if (arguments.callee.listener) {
        // set proxyFrom for access in bound event handlers
        event.proxyFrom = arguments.callee.elem;
        // call the root "handle" function on the listener
        jQuery.event.handle.apply(arguments.callee.listener, arguments);
        // if we got a result of false from the event callbacks - exit early
        if (event.result === false) return;
        // clean that proxy property out
        delete event.proxyFrom;
      }
      // this is all the basic 'handle' function does:
      jQuery.event.handle.apply(arguments.callee.elem, arguments);
    };
    // properties of the handler function
    newHandle.elem = fromObject;
    newHandle.listener = toObject;
    // store it
    jQuery.data(fromObject, 'handle', newHandle);
  };
  jQuery.event.proxyEvents(origTarget, otherObject);