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

Posted

技术标签:

【中文标题】孩子们如何收听/捕捉父母的事件【英文标题】:how can the children listen/capture to the parent's event 【发布时间】:2012-09-12 07:19:14 【问题描述】:

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

<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])时,子级无法捕获该事件。

有什么解决办法吗?

【问题讨论】:

我相信这是不可能的,除非你做出某种破解,因为事件像气泡一样在 DOM 树上上升,永远不会下降到孩子 【参考方案1】:

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

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

addEventListener (type, listener[, useCapture])

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

基本上,如果您使用true 作为最后一个参数,则事件侦听器应在捕获阶段触发(当事件沿着 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' );
);

【讨论】:

感谢您的回复,但根据 w3c,使用 addEventListener 和第三个参数作为 true 将执行事件的捕获阶段,但是,我已经更新了代码而不使用 jQuery(这里是新代码jsfiddle.net/EDjqu/4),但捕获阶段似乎仍然无法正常工作 是的,我自己才意识到这一点......我想我应该测试一下,因为我不知道它是否会......这导致我构建了一个快速的 jQuery 插件。跨度> 谢谢,我想我别无选择,只能遍历孩子们,就像@haynar 对帖子的评论一样 完全不用担心.. :) 我要说的一件事是 haynar 的解决方案是硬编码为特定标识符的,并且必须在 div1 上设置 customEvent2 - 不理想 (正如他承认的那样) - 我不建议您这样做(除非您只是一次性实现这些事件侦听器)。上述插件的工作方式与$().trigger 在支持任何事件、传递额外参数方面的工作方式完全相同,并且可以处理父级和子级之间的任何距离......这将使您的代码更整洁,更易于管理, & 更符合 jQuery 的精神。【参考方案2】:

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

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

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

代码 sn-p 借用自 jQuery.bind-first library v0.1 Vladimir Zhuravlev

【讨论】:

+1 非常好的一点 - 完全没有想到 - 当我得到第二个时,我需要进行修改:)【参考方案3】:

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

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

【讨论】:

这正是我不想要的,例如我有 div2_a、div2_b、div2_c .....也许还有更多,然后我必须通过所有 div2 以防触发事件【参考方案4】:

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

【讨论】:

以上是关于孩子们如何收听/捕捉父母的事件的主要内容,如果未能解决你的问题,请参考以下文章

Qt:让父母决定孩子是不是接受事件

javascript 从孩子发出事件,听父母vujs

将数据从孩子传递给父母,而无需加载事件,这可能在 vue 世界上吗?

VUE 有没有办法使用 :click 事件在父母姓名下显示孩子姓名?

如何让“Pointermove”委托在父母/孩子的Safari iOS中工作?

为啥我无法捕捉到父母发送的孩子的信号?