将后续点击延迟 2 秒或在网页 AJAX 调用之后

Delay subsequent clicks either 2 seconds or after webpage AJAX call

对于 Firefox WebExtension,我需要点击网页中的多个单选按钮。
因此,通过browser.tabs.executeScript()调用以下代码:

var items = "input[id^='M37_Q_'][id$='_B1']";
var first_item = items + ":first";
$('html, body').animate({
    scrollTop: $(first_item).offset().top
}, 1000);
$(items).click();

但是,原始单选按钮连接到 AJAX 调用(即保存实际状态),并且使用上面的代码,10 个按钮中只有 2 个被点击。

底层HTML代码如下(字面意思就是几十条)

<div class="radio">
    <label class="" for="M37_Q_POSWECHSEL_BETT_B1">
        <input type="radio" id="M37_Q_POSWECHSEL_BETT_B1" name="M37_Q_POSWECHSEL_BETT" value="B1" aria-describedby="M37_Q_POSWECHSEL_BETT_error_0" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETT#B1">
        0
    </label>    
</div>

另外,我没有(写入)源代码的访问权限,也没有服务器端的访问权限,这确实是问题的一部分。

现在我的问题是:如何稍微延迟 "next" 单击,以便仅在第一个 AJAX 调用成功完成时(或经过一段时间,比如 2 秒)才单击它)?

在点击之间添加 2 秒的延迟

只需在每个 click() 之间添加 2 秒的延迟就相当容易了。您可以使用 setTimeout() 循环来做到这一点。

jQuery

使用 jQuery 在点击之间实现 2 秒的延迟,可能类似于:

var items = "input[id^='M37_Q_'][id$='_B1']";

function clickOnceEvery2s($list) {
    if($list.length > 0) {
        //Click the first jQuery object in the list
        $list[0].click();
        //Remove the first jQuery object in the list
        $list.splice(0,1); //jQuery Objects are not actually arrays, but do have .splice().
        if($list.length > 0) {
            //If there are more, do the next one after a 2 second delay. Also check here
            //  for length > 0 so there's not a timeout hanging around which will do
            //  nothing.
            setTimeout(clickOnceEvery2s,2000,$list);
        }
    }
}
clickOnceEvery2s($(items));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="radio">
  <label class="" for="M37_Q_POSWECHSEL_BETT_B1">
    <input type="radio" id="M37_Q_POSWECHSEL_BETT_B1" name="M37_Q_POSWECHSEL_BETT" value="B1" aria-describedby="M37_Q_POSWECHSEL_BETT_error_0" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETT#B1">
    T0
  </label>
  <label class="" for="M37_Q_POSWECHSEL_BETT_B2">
    <input type="radio" id="M37_Q_POSWECHSEL_BETT_B2" name="M37_Q_POSWECHSEL_BETT" value="B2" aria-describedby="M37_Q_POSWECHSEL_BETT_error_1" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETT#B2" checked>
    T1
  </label>
  <br/>
  <label class="" for="M37_Q_POSWECHSEL_BETU_B1">
    <input type="radio" id="M37_Q_POSWECHSEL_BETU_B1" name="M37_Q_POSWECHSEL_BETU" value="B1" aria-describedby="M37_Q_POSWECHSEL_BETU_error_0" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETU#B1">
    U0
  </label>
  <label class="" for="M37_Q_POSWECHSEL_BETU_B2">
    <input type="radio" id="M37_Q_POSWECHSEL_BETU_B2" name="M37_Q_POSWECHSEL_BETU" value="B2" aria-describedby="M37_Q_POSWECHSEL_BETU_error_1" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETU#B2" checked>
    U1
  </label>
  <br/>
  <label class="" for="M37_Q_POSWECHSEL_BETV_B1">
    <input type="radio" id="M37_Q_POSWECHSEL_BETV_B1" name="M37_Q_POSWECHSEL_BETV" value="B1" aria-describedby="M37_Q_POSWECHSEL_BETV_error_0" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETV#B1">
    V0
  </label>
  <label class="" for="M37_Q_POSWECHSEL_BETV_B2">
    <input type="radio" id="M37_Q_POSWECHSEL_BETV_B2" name="M37_Q_POSWECHSEL_BETV" value="B2" aria-describedby="M37_Q_POSWECHSEL_BETV_error_1" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETV#B2" checked>
    V1
  </label>
  <br/>
  <label class="" for="M37_Q_POSWECHSEL_BETW_B1">
    <input type="radio" id="M37_Q_POSWECHSEL_BETW_B1" name="M37_Q_POSWECHSEL_BETW" value="B1" aria-describedby="M37_Q_POSWECHSEL_BETW_error_0" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETW#B1">
    W0
  </label>
  <label class="" for="M37_Q_POSWECHSEL_BETW_B2">
    <input type="radio" id="M37_Q_POSWECHSEL_BETW_B2" name="M37_Q_POSWECHSEL_BETW" value="B2" aria-describedby="M37_Q_POSWECHSEL_BETW_error_1" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETW#B2" checked>
    W1
  </label>
  <br/>
  <label class="" for="M37_Q_POSWECHSEL_BETX_B1">
    <input type="radio" id="M37_Q_POSWECHSEL_BETX_B1" name="M37_Q_POSWECHSEL_BETX" value="B1" aria-describedby="M37_Q_POSWECHSEL_BETX_error_0" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETX#B1">
    X0
  </label>
  <label class="" for="M37_Q_POSWECHSEL_BETX_B2">
    <input type="radio" id="M37_Q_POSWECHSEL_BETX_B2" name="M37_Q_POSWECHSEL_BETX" value="B2" aria-describedby="M37_Q_POSWECHSEL_BETX_error_1" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETX#B2" checked>
    X1
  </label>
    <br/>
  <label class="" for="M37_Q_POSWECHSEL_BETY_B1">
    <input type="radio" id="M37_Q_POSWECHSEL_BETY_B1" name="M37_Q_POSWECHSEL_BETY" value="B1" aria-describedby="M37_Q_POSWECHSEL_BETY_error_0" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETY#B1">
    Y0
  </label>
  <label class="" for="M37_Q_POSWECHSEL_BETY_B2">
    <input type="radio" id="M37_Q_POSWECHSEL_BETY_B2" name="M37_Q_POSWECHSEL_BETY" value="B2" aria-describedby="M37_Q_POSWECHSEL_BETY_error_1" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETY#B2" checked>
    Y1
  </label>
  <br/>
</div>

原版 JavaScript

如果 jQuery 不是真正需要的,在 vanilla JavaScript.

中实现同样的事情也很容易

var items = "input[id^='M37_Q_'][id$='_B1']";

function clickOnceEvery2s(array) {
    if(array.length > 0) {
        //Click the first element in the Array
        array[0].click();        
        //Remove the element from the Array
        array.shift();
        if(array.length > 0) {
            //If there are more, do the next one after a 2 second delay. Also check here
            //  for length > 0 so there's not a timeout hanging around which will do
            //  nothing.
            setTimeout(clickOnceEvery2s,2000,array);
        }
    }
}
//Pass the elements in an Array. Uses the spread operator to convert NodeList to Array.
clickOnceEvery2s([...document.querySelectorAll(items)]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="radio">
  <label class="" for="M37_Q_POSWECHSEL_BETT_B1">
    <input type="radio" id="M37_Q_POSWECHSEL_BETT_B1" name="M37_Q_POSWECHSEL_BETT" value="B1" aria-describedby="M37_Q_POSWECHSEL_BETT_error_0" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETT#B1">
    T0
  </label>
  <label class="" for="M37_Q_POSWECHSEL_BETT_B2">
    <input type="radio" id="M37_Q_POSWECHSEL_BETT_B2" name="M37_Q_POSWECHSEL_BETT" value="B2" aria-describedby="M37_Q_POSWECHSEL_BETT_error_1" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETT#B2" checked>
    T1
  </label>
  <br/>
  <label class="" for="M37_Q_POSWECHSEL_BETU_B1">
    <input type="radio" id="M37_Q_POSWECHSEL_BETU_B1" name="M37_Q_POSWECHSEL_BETU" value="B1" aria-describedby="M37_Q_POSWECHSEL_BETU_error_0" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETU#B1">
    U0
  </label>
  <label class="" for="M37_Q_POSWECHSEL_BETU_B2">
    <input type="radio" id="M37_Q_POSWECHSEL_BETU_B2" name="M37_Q_POSWECHSEL_BETU" value="B2" aria-describedby="M37_Q_POSWECHSEL_BETU_error_1" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETU#B2" checked>
    U1
  </label>
  <br/>
  <label class="" for="M37_Q_POSWECHSEL_BETV_B1">
    <input type="radio" id="M37_Q_POSWECHSEL_BETV_B1" name="M37_Q_POSWECHSEL_BETV" value="B1" aria-describedby="M37_Q_POSWECHSEL_BETV_error_0" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETV#B1">
    V0
  </label>
  <label class="" for="M37_Q_POSWECHSEL_BETV_B2">
    <input type="radio" id="M37_Q_POSWECHSEL_BETV_B2" name="M37_Q_POSWECHSEL_BETV" value="B2" aria-describedby="M37_Q_POSWECHSEL_BETV_error_1" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETV#B2" checked>
    V1
  </label>
  <br/>
  <label class="" for="M37_Q_POSWECHSEL_BETW_B1">
    <input type="radio" id="M37_Q_POSWECHSEL_BETW_B1" name="M37_Q_POSWECHSEL_BETW" value="B1" aria-describedby="M37_Q_POSWECHSEL_BETW_error_0" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETW#B1">
    W0
  </label>
  <label class="" for="M37_Q_POSWECHSEL_BETW_B2">
    <input type="radio" id="M37_Q_POSWECHSEL_BETW_B2" name="M37_Q_POSWECHSEL_BETW" value="B2" aria-describedby="M37_Q_POSWECHSEL_BETW_error_1" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETW#B2" checked>
    W1
  </label>
  <br/>
  <label class="" for="M37_Q_POSWECHSEL_BETX_B1">
    <input type="radio" id="M37_Q_POSWECHSEL_BETX_B1" name="M37_Q_POSWECHSEL_BETX" value="B1" aria-describedby="M37_Q_POSWECHSEL_BETX_error_0" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETX#B1">
    X0
  </label>
  <label class="" for="M37_Q_POSWECHSEL_BETX_B2">
    <input type="radio" id="M37_Q_POSWECHSEL_BETX_B2" name="M37_Q_POSWECHSEL_BETX" value="B2" aria-describedby="M37_Q_POSWECHSEL_BETX_error_1" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETX#B2" checked>
    X1
  </label>
    <br/>
  <label class="" for="M37_Q_POSWECHSEL_BETY_B1">
    <input type="radio" id="M37_Q_POSWECHSEL_BETY_B1" name="M37_Q_POSWECHSEL_BETY" value="B1" aria-describedby="M37_Q_POSWECHSEL_BETY_error_0" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETY#B1">
    Y0
  </label>
  <label class="" for="M37_Q_POSWECHSEL_BETY_B2">
    <input type="radio" id="M37_Q_POSWECHSEL_BETY_B2" name="M37_Q_POSWECHSEL_BETY" value="B2" aria-describedby="M37_Q_POSWECHSEL_BETY_error_1" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETY#B2" checked>
    Y1
  </label>
  <br/>
</div>

在 AJAX 调用 returns

之后执行

执行此操作的方法是覆盖用于进行 AJAX 调用的方法。如果呼叫是通过 jQuery 的 .ajax() method, then you can override that. However, normally, you would override XMLHttpRequest() 完成的。您将保存真实方法的副本并插入一个从页面的角度来看,其功能与常用方法相同的方法。但是,您的代码将随响应一起调用,这样您就可以知道请求何时完成。这要复杂得多。此外,问题中没有足够的信息让我们能够唯一识别 AJAX 调用。因此,我们能做的最好的事情就是寻找在 .click() 之后发起的 AJAX 调用,然后等待 AJAX 调用完成。虽然这很可能是正确的 AJAX 调用,但如果没有更多信息,我们无法确定它是正确的 AJAX 调用。

潜在优化

取决于触发 AJAX 调用的页面代码,以及执行 AJAX 调用的代码是否读取所有单选按钮的状态(即不仅仅是那个被点击),您可以一次更改所有单选按钮的状态。可行的方法是在所有需要的单选按钮上设置 checked 属性。然后,您可以触发单个 click 事件来触发 AJAX 调用。如果这有效,那么您不需要等待 AJAX 调用 return 来更改后续的单选按钮。您一次更改所有按钮,页面仅调用一次 AJAX 来更改所有按钮的记录状态。如果没有您正在更改的页面的实际代码,我们无法知道这是否可行,但您可以尝试类似的方法:

var items = "input[id^='M37_Q_'][id$='_B1']";
$(items).attr('checked','true')[0].click();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="radio">
  <label class="" for="M37_Q_POSWECHSEL_BETT_B1">
    <input type="radio" id="M37_Q_POSWECHSEL_BETT_B1" name="M37_Q_POSWECHSEL_BETT" value="B1" aria-describedby="M37_Q_POSWECHSEL_BETT_error_0" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETT#B1">
    T0
  </label>
  <label class="" for="M37_Q_POSWECHSEL_BETT_B2">
    <input type="radio" id="M37_Q_POSWECHSEL_BETT_B2" name="M37_Q_POSWECHSEL_BETT" value="B2" aria-describedby="M37_Q_POSWECHSEL_BETT_error_1" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETT#B2" checked>
    T1
  </label>
  <br/>
  <label class="" for="M37_Q_POSWECHSEL_BETU_B1">
    <input type="radio" id="M37_Q_POSWECHSEL_BETU_B1" name="M37_Q_POSWECHSEL_BETU" value="B1" aria-describedby="M37_Q_POSWECHSEL_BETU_error_0" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETU#B1">
    U0
  </label>
  <label class="" for="M37_Q_POSWECHSEL_BETU_B2">
    <input type="radio" id="M37_Q_POSWECHSEL_BETU_B2" name="M37_Q_POSWECHSEL_BETU" value="B2" aria-describedby="M37_Q_POSWECHSEL_BETU_error_1" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETU#B2" checked>
    U1
  </label>
  <br/>
  <label class="" for="M37_Q_POSWECHSEL_BETV_B1">
    <input type="radio" id="M37_Q_POSWECHSEL_BETV_B1" name="M37_Q_POSWECHSEL_BETV" value="B1" aria-describedby="M37_Q_POSWECHSEL_BETV_error_0" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETV#B1">
    V0
  </label>
  <label class="" for="M37_Q_POSWECHSEL_BETV_B2">
    <input type="radio" id="M37_Q_POSWECHSEL_BETV_B2" name="M37_Q_POSWECHSEL_BETV" value="B2" aria-describedby="M37_Q_POSWECHSEL_BETV_error_1" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETV#B2" checked>
    V1
  </label>
  <br/>
  <label class="" for="M37_Q_POSWECHSEL_BETW_B1">
    <input type="radio" id="M37_Q_POSWECHSEL_BETW_B1" name="M37_Q_POSWECHSEL_BETW" value="B1" aria-describedby="M37_Q_POSWECHSEL_BETW_error_0" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETW#B1">
    W0
  </label>
  <label class="" for="M37_Q_POSWECHSEL_BETW_B2">
    <input type="radio" id="M37_Q_POSWECHSEL_BETW_B2" name="M37_Q_POSWECHSEL_BETW" value="B2" aria-describedby="M37_Q_POSWECHSEL_BETW_error_1" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETW#B2" checked>
    W1
  </label>
  <br/>
  <label class="" for="M37_Q_POSWECHSEL_BETX_B1">
    <input type="radio" id="M37_Q_POSWECHSEL_BETX_B1" name="M37_Q_POSWECHSEL_BETX" value="B1" aria-describedby="M37_Q_POSWECHSEL_BETX_error_0" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETX#B1">
    X0
  </label>
  <label class="" for="M37_Q_POSWECHSEL_BETX_B2">
    <input type="radio" id="M37_Q_POSWECHSEL_BETX_B2" name="M37_Q_POSWECHSEL_BETX" value="B2" aria-describedby="M37_Q_POSWECHSEL_BETX_error_1" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETX#B2" checked>
    X1
  </label>
    <br/>
  <label class="" for="M37_Q_POSWECHSEL_BETY_B1">
    <input type="radio" id="M37_Q_POSWECHSEL_BETY_B1" name="M37_Q_POSWECHSEL_BETY" value="B1" aria-describedby="M37_Q_POSWECHSEL_BETY_error_0" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETY#B1">
    Y0
  </label>
  <label class="" for="M37_Q_POSWECHSEL_BETY_B2">
    <input type="radio" id="M37_Q_POSWECHSEL_BETY_B2" name="M37_Q_POSWECHSEL_BETY" value="B2" aria-describedby="M37_Q_POSWECHSEL_BETY_error_1" aria-invalid="true" data-clipboard="M37_Q_POSWECHSEL_BETY#B2" checked>
    Y1
  </label>
  <br/>
</div>
<script>
    $('input').click(function(event) {
        console.log('A radio button was clicked.');
    });
</script>