孩子们如何倾听/捕捉父母的事件

时间:2012-09-19 22:43:32

标签: javascript html5 dom javascript-events

父如何激活自定义事件以通知其子/兄弟姐妹? 例如:

<div id="div1">
   <div id="div2"></div>
</div>

div2有addEventListener('customEvent2',doSth),然后div1将触发一个自定义事件(customEvnet2)。但这永远不会触发div2的“doSth”功能

示例代码:http://jsfiddle.net/r4tcT/2/

“div 1触发器customEvent 2”按钮永远不会起作用

所以当父母发起自定义事件(dispatchEvent [IE9] / fireEvent [IE9 - ] / trigger [jQuery])时,孩子们无法捕获事件。

有没有解决方法?

4 个答案:

答案 0 :(得分:6)

您所谈论的差异是“捕获”事件模型或“冒泡”事件模型之间。 jQuery的触发器可以在Bubble模型上运行,因为这是更受支持的事件模型 - 主要得益于Internet Explorer。泡泡模型只向后移动通过元素父母......这就是为什么你的事件在div2div1触发时不会触发的原因,因为它始终冒泡而不是向下。

我之前没有使用本机函数尝试过自定义事件,但大多数现代浏览器允许您决定在设置事件监听器时使用哪种类型的模型:

addEventListener (type, listener[, useCapture])

https://developer.mozilla.org/en-US/docs/DOM/element.addEventListener

基本上,如果您使用true作为最终参数,则事件侦听器应在Capture阶段中触发(这是事件沿着dom树向下移动时)。如果设置为false,则事件将在冒泡阶段触发,该阶段在向后返回dom树时发生。

这已在此处讨论过:

Event Capturing vs Event Bubbling

正如我所说,这是否适用于定制活动,我不确定。我很确定你不能用jQuery (截至目前)来做这件事可能是由于旧浏览器缺乏支持。

校正

我在上面猜到的似乎不起作用。我认为由于“捕获”这一术语会让你考虑捕获用户输入 - 当涉及定制事件时,无法定义新的用户输入。所以考虑到这一点,我把这个快速的jQuery插件放在一起...它只是经过粗略测试,但逻辑应该是合理的 - 希望它有用:

/**
 * unbubble v0.2
 *
 * trigger an event down through the children of a collection, 
 * rather than up through it's parents
 *
 *  @update 2013/03/18 - fixed the problem of triggering bubble phase each
 *    step down the element tree as pointed out by @vine.
 */
$.fn.unbubble = function( eventNames ){
  var names = eventNames.split(' '), 
      non = names.length, 
      args = Array.prototype.slice.call(arguments);
  /// our own trigger function designed to bubble down... not up!
  var trigger = function(){
    var i, events, elm = $(this);
    /// make sure we can read the events array
    if ( $._data ) {
      /// make sure events is defined
      if ( (events = $._data(this, 'events')) ) {
        /// do a quick check, saves firing trigger on every element found
        for ( i=0; i<non; i++ ) {
          /// make sure our eventName appears in the event list
          if ( names[i] && ( names[i] in events ) ) {
            /// trigger the standard jQuery trigger function
            elm.triggerHandler.apply(elm, args);
            /// escape as trigger should fire for multiple names
            break;
          }
        }
      }
    }
    /// if we can't access the events array, just trigger and hope
    else {
      /// trigger the standard jQuery trigger function
      elm.triggerHandler.apply(elm, args);
    }
    /// trigger for all the children, and on, and on...
    elm.children().each(trigger);
  };
  /// foreach element trigger now...
  this.each(trigger);
}

/**
 * Example usage
 */
$(function(){
  /// bind our event as usual
  $('.div2').bind('customEvent', function(){
    alert('I should trigger!');
  });
  /// rather than use trigger, fire with unbubble
  $('#div1').unbubble( 'customEvent' );
});

答案 1 :(得分:1)

pebbl的答案很好,但它有缺陷。捕获阶段以某种方式通过从文档到相关元素的正常触发事件来模拟。但问题是,在任何元素上调用标准jQuery触发器函数后会立即出现从该元素开始的冒泡阶段。所以我相信他可以直接从元素集合中访问事件数据并直接调用它而不使用标准触发函数,就像这样

var JQ_LT_17 = parseFloat($.fn.jquery) < 1.7;

function getEventsData(element) {
        return JQ_LT_17 ? $(element).data('events') : $._data(element).events;
}

从jQuery.bind-first library v0.1 Vladimir Zhuravlev借用的代码片段

答案 2 :(得分:0)

customEvent2仅限于div2。当您尝试在div1上触发它时,没有任何反应,因为div1不存在该事件。

如果要触发customEvent2,则必须在它实际绑定的元素(或其子元素)上触发它。

答案 3 :(得分:0)

我玩了一些代码,here就是我现在所拥有的。这是一个黑客,但也许它可以帮助你解决你的问题?