【问题标题】:Stop propagation doesn't work停止传播不起作用
【发布时间】:2015-10-10 16:52:48
【问题描述】:

我有以下 JQuery eventhandler。我想停止网页上的所有导航。

$(document).click(function(event) {
            event.stopPropagation();
            event.preventDefault();
            event.cancelBubble = true;
            event.stopImmediatePropagation();
            $(document).css('border-color','');
            $(document).css('background-color',''); 
            $(event.target).css('border-color','yellow');
            $(event.target).css('background-color','#6BFF70');
            return false;
    });

当我在 Facebook 登录页面上使用它时,它会停止所有导航。但在 Google 主页中,“手气不错”按钮仍会导航到下一页。如何避免?

顺便说一下,我正在使用 JavaFX 浏览器。类似于 Safari 浏览器。

【问题讨论】:

  • 我尝试使用 $('*')。仍然是相同的行为。
  • 如果你只是想阻止任何用户输入,我会添加一个覆盖所有正文的 div
  • @Haketo,我必须在浏览器中加载的任何网站上执行此操作。我没有自己的 HTML。
  • 事件的传播是在元素之间;如果用户直接单击一个带有直接附加处理程序的元素,则停止单击事件的传播不会阻止该事件触发。看到这个小提琴:jsfiddle.net/ejreseuu。单击子元素时,无法阻止记录“click2”;传播在触发“click1”事件之前被正确取消,但无法在“click2”事件触发之前捕获事件并停止它。

标签: javascript jquery javafx


【解决方案1】:

如果我加载 Google 搜索页面,并在控制台执行此操作:

document.body.addEventListener(
  "click", 
  function (ev) { ev.stopPropagation(); ev.preventDefault(); },
  true);

然后我不能再点击“手气不错”按钮了。关键是使用第三个参数,设置为true。以下是 MDN [说] 关于它的内容:

useCapture 可选

如果为真,useCapture 表示用户希望启动捕获。启动捕获后,所有指定类型的事件将被分派到注册的侦听器,然后再分派到 DOM 树中其下方的任何EventTarget

(已添加重点。)

您尝试执行的操作不起作用,因为您的事件处理程序位于document,因此将在文档子项上的任何事件处理程序之后调用。所以你的处理程序不能阻止任何事情。

useCapture 设置为true,您可以在事件有机会传递给子元素之前对其进行操作。我不知道有一种方法可以让 jQuery 的事件处理程序以您使用 useCapture 的方式工作。 Barmar 的answer here 说你不能使用jQuery 来设置这样的处理程序。我倾向于相信他。

【讨论】:

  • 绝对是最好的原生 javascript 点击父 div 的内部元素,无需传播点击父 div。它工作得非常完美!谢谢
  • useCapture 对我没有任何影响,但添加 ev.preventDefault() 最终停止了冒泡
【解决方案2】:

由于我评论的原因,99.99% 的网页将无法通过停止事件传播来停止导航(您无法在事件触发事件初始目标的所有处理程序之前停止事件)。如果您只对阻止导航感兴趣,我建议使用 window.onbeforeunload 事件,该事件专门针对这种情况。

这里是一个例子:http://jsfiddle.net/ejreseuu/

HTML:

<a href="google.com">google</a>

JS:

window.onbeforeunload = function() {
    return "Are you sure?"
}

据我所知,没有确认框是不可能的,因为无论用户做什么都会阻止用户离开的代码通常是恶意的。

【讨论】:

    【解决方案3】:

    preventDefault() 在这种情况下应该不起作用,因为 Google 依靠自定义 事件侦听器 来处理此按钮上的点击事件。虽然 preventDefault() 防止浏览器的默认行为。

    例如,如果此按钮的类型为“提交”,则阻止默认点击事件将阻止浏览器的默认行为,即提交表单。但在这种情况下,单击由添加到按钮本身的 eventListeners 处理。 preventDefault() 不会影响他们捕获事件。也不是 stopPropagation(),因为它会停止将事件传播到更高级别的 DOM,而同一级别的其他 eventListener(在我们的例子中是按钮)仍然会收到事件。 stopImmediatePropagation() 理论上可以工作,但前提是您的 eventListener 是在 google 之前添加的。

    因此,停止传播的最简单方法是在事件到达按钮节点之前停止事件,这是在捕获阶段,因为按钮是层次结构中的最低元素。这可以通过在添加 eventListener 时传递 true 参数来完成

    document.body.addEventListener("click", function (event) { 
      event.stopPropagation();
    }, true);
    

    这种方式事件将在冒泡阶段之前停止,因此在它到达添加到按钮的 eventListeners 之前。更多关于捕获和冒泡阶段here

    请注意,在这种情况下不需要 preventDefault()。实际上,这个按钮的事件监听器是为了防止自己默认。下面是那些事件监听器,分别用于 click 和 keyup:

    d = function(a) {
     c.Xa.search(c.yc(), b);
     return s_1vb(a)
    }
    
    function(a) {
     13 != a.keyCode && 32 != a.keyCode || d(a)
    }
    

    注意对 s_1vb 的调用,这是它的来源:

    s_1vb.toString();
    /*"function (a){
         a&&(a.preventDefault&&a.preventDefault(),a.returnValue=!1);
         return!1
      }"*/
    

    基本上它是一个接受事件并尽一切可能阻止浏览器默认行为的函数

    顺便说一句,默认行为可以在事件流的任何阶段(se Events Specification)取消,包括最后一个阶段,当它到达文档时。只有在它“通过”所有未取消的事件监听器之后,浏览器才应该执行其默认行为。因此,将您的侦听器附加到文档并不是 preventDefault() 不起作用的原因,而是因为它不适合这项工作:)

    【讨论】:

      【解决方案4】:

      试试这个:

      $('body').click(function(event) {
                  event.stopPropagation();
                  event.preventDefault();
                  event.cancelBubble = true;
                  event.stopImmediatePropagation();
                  $(document).css('border-color','');
                  $(document).css('background-color',''); 
                  $(event.target).css('border-color','yellow');
                  $(event.target).css('background-color','#6BFF70');
                  return false;
          });
      

      【讨论】:

        【解决方案5】:

        尝试不仅绑定到click 事件,还绑定到mousedown 事件。

        【讨论】:

          【解决方案6】:

          试试这个 CSS:

           body * {
              pointer-events: none;
           }
          

          或在 jQuery 中:

           $("body *").css("pointer-events", "none");
          

          【讨论】:

            【解决方案7】:

            尝试声明一个新的窗口事件,然后从那里停止传播:

            var e = window.event;
            e.cancelBubble = true;
            if (e.stopPropagation)
            {
               e.stopPropagation();
            }
            

            【讨论】:

              【解决方案8】:

              请注意,Google 使用 jsaction="..." 而不是 onclick="..."。尝试在指定按钮上使用它的 unbind 方法。

              你也可以使用动态附件,比如:

              $(document).on('click', '*', function
              

              或者throw new Error()(就像一个肮脏的黑客)

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2012-08-24
                • 2013-01-04
                • 2011-03-31
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多