12

父母如何触发自定义事件以通知其孩子/兄弟姐妹?例如:

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

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

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

“div 1 trigger customEvent 2”按钮永远不起作用

因此,当父级触发自定义事件(dispatchEvent[IE9]/fireEvent[IE9-]/trigger[jQuery])时,子级无法捕获该事件。

有什么解决方法吗?

4

4 回答 4

6

您正在谈论的区别在于“捕获”事件模型或“冒泡”事件模型之间。jQuery 的触发器在 Bubble 模型上运行可能是因为这是更受支持的事件模型——主要归功于 Internet Explorer。Bubble 模型仅通过元素父母向后移动......这就是为什么您的事件在从 触发div2时不会触发的原因div1,因为它总是在冒泡而不是向下。

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

addEventListener (type, listener[, useCapture])

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

基本上,如果您将事件侦听器true用作最后一个参数,则事件侦听器应在 Capture 阶段(即事件沿 dom 树传播时)触发。如果设置为 false,则事件将在返回 dom 树时发生的冒泡阶段触发。

这已经在这里讨论过:

事件捕获与事件冒泡

正如我所说,这是否适用于定制活动,我不确定。我很确定你不能用 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' );
});
于 2012-09-19T22:57:02.040 回答
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

于 2012-09-24T07:25:21.037 回答
0

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

于 2012-09-19T23:01:12.540 回答
0

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

如果你想触发customEvent2,它必须在它实际绑定的元素(或一个元素的子元素)上触发。

于 2012-09-19T22:52:14.773 回答