其他JavaScript事件监听器是否可以等待异步事件?

4
我想使用Tampermonkey劫持一个网页,该页面有一个带有某些事件监听器和最终重定向的按钮。
有没有办法向该按钮添加自己的点击事件处理程序,使其发出AJAX请求,并在继续处理其他事件监听器之前等待它完成,以便我的AJAX请求在重定向之前肯定已经完成?
我知道stopImmediatePropagation,但不知道如何异步“延迟”传播。

不,一般情况下是不可能的。但是有一些 ExtendableEvent 可以做到这一点,尽管它们并不在所有地方都被触发。 - Bergi
1个回答

3
不,你不能让其他事件处理程序等待。有时候可以覆盖/劫持现有函数,但在Tampermonkey中通常不可能,并且当它是可能的时会变得混乱(例如在Firefox + Greasemonkey中)。
对于可点击的元素(如按钮),一种解决方法是叠加按钮,为其设置监听器,然后在需要时触发原始按钮上的所需事件。
例如,考虑下面的代码片段:
1. #mainButton及其代码代表原始页面。 2. “Hijack”按钮模拟运行您的Tampermonkey脚本。 3. “script”创建了一个与按钮大小相同的div,并将其定位在按钮上方。因此,任何点击都被div捕获,而不是按钮。 4. 拦截代码执行一些异步操作,然后触发原始按钮上的点击。

//--------------------------
//--- The page's code:
//--------------------------
$("#mainButton").click ( function () {
    logline ("The button was clicked.");
} );

//------------------------------
//--- The script setup and code:
//------------------------------
$("#tmIntercept").click ( function () {
    logline ("==> Main button is now intercepted.");
    //this.disabled = true;
    $(this).attr ( {"disabled": true} );

    var targBtn     = $("#mainButton");
    var overlayDiv  = $('<div id="tmBtnOverlay">').css ( {
        'width':        targBtn.outerWidth (),
        'height':       targBtn.outerHeight (),
        'position':     'absolute',
        'top':          targBtn.offset ().top,
        'left':         targBtn.offset ().left,
        'z-index':      8888,
        'background':   "lime",
        'opacity':      "0.2"
    } )
    .appendTo ("body");

    overlayDiv.click ( function (zEvent) {
        //-- Guard against more global handlers.
        zEvent.stopImmediatePropagation ();

        logline ("Doing some AJAXy thing... <span>&nbsp;</span>");

        //-- Simulated AJAX call:
        setTimeout (doSomeAjaxyThing, 1111);
    } );
} );

function doSomeAjaxyThing () {
    $("#eventLog > p > span").first ().text ('Done.');

    //-- Now send required events to the original button:
    var clickEvent = document.createEvent ('MouseEvents');
    clickEvent.initEvent ("click", true, true);
    $("#mainButton")[0].dispatchEvent (clickEvent);
}

function logline (str) {
    this.lineNumber = this.lineNumber + 1  ||  1;
    var lineDisplay = (1e15 + this.lineNumber + "").slice (-3);  //-- zero pad 3 places

    $("#eventLog").prepend ('<p>' + lineDisplay + ' &nbsp; ' + str + '</p>');
}
#mainButton {
    font-size: 2em;
    padding: 0.3ex 2ex;
}
#eventLog {
    max-height: 50vh;
    overflow-y: auto;
    overflow-x: hidden;
}
#eventLog > p {
    margin: 0.3ex 2ex;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>

<p><button id="mainButton">The Button</button></p>

<p><button id="tmIntercept" autocomplete="off">Hijack the button</button></p>

<fieldset>
    <legend>Event Log:</legend>
    <div id="eventLog"></div>
</fieldset>


注意事项:

  1. 在某些情况下,您可能会直接调用页面的代码。但是,触发事件通常更简单、更健壮、更安全。
  2. 这只是一个覆盖层过程的演示。实际上,简单的绝对定位可能需要微调。(通常将目标节点包装在相对定位的div中并调整偏移量。)这超出了本问题的范围。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接