3

因此,我当前的项目还有另一个小的 JavaScript 问题:JS 事件没有按照我期望的顺序触发。

假设我有一个带有 onBlur 事件的文本字段,该事件触发一个 AJAX 调用,该调用在服务器上进行一些计算(我正在使用 .NET 3.5 的带有 JSON 的 WebServices)。它的回调方法使用计算结果填充一个充满文本字段的页面。

我还有一个带有 onClick 事件的按钮,它启动不同的计算,但它依赖于在其 onClick 事件的结果有效之前完成文本字段的 onBlur 事件。

我有一个简单的互斥锁,它工作得很好,直到出现以下情况:用户更改了其中一个文本字段中的值但还没有离开它,所以焦点仍然在文本字段上。当文本字段具有焦点时,他们单击具有 onClick 事件的按钮。 通常情况下,浏览器(在本例中为 IE7)会在文本字段的 onBlur 事件之前触发按钮的 onClick 事件!

这会造成一些破坏,我不知道如何强制执行被触发的事件的顺序。我的小互斥锁的工作方式如下:当任何事件被触发时,我设置一个表示“等待回调”的标志。任何触发的后续事件在执行任何操作之前都会检查标志。在回调中将标志重置为 false。

那么,有什么想法吗?我想我几乎想让所有的 Web 服务调用同步,但我不知道是否有一种简单的方法可以做到这一点。

我尝试过的其他事情或您应该知道的事情: - 禁用文本字段的 onBlur 中的按钮 - 它们的 onClick 在被禁用之前仍然会触发 - 请记住,这只发生在编辑文本字段并立即单击按钮。如果用户在单击按钮之前单击空白区域以触发文本字段的 onBlur,则一切正常。

编辑:

经过一些评论和更多测试,这就是我想要做的:

在文本字段的 onBlur 中,我想禁用该按钮,以便它的 onClick 事件不会触发。但是,当我编写代码时,onBlur 事件会触发,我可以看到按钮被禁用,但它的 onClick 事件仍在触发。

这是一些示例代码。 有时会发生 onClick 事件,有时不会发生。 如果您将 setTimeout 设置为 500 毫秒左右,它似乎总是会阻止它。也许这是一个选择...

<html>
<head>
<script type="text/javascript">

var onClickFlag = false;

function whatHappensOnFocus(el) {
    log('whatHappensOnFocus(): TextField focused.');
    onClickFlag = false;
    log('whatHappensOnFocus(): Set onClickFlag = false');
}

function whatHappensOnBlur(el) {
    log('whatHappensOnBlur(): TextField blurred.');
    document.getElementById('theButton').disabled = true;
    log('whatHappensOnBlur(): Disabled the Button');
    setTimeout(function() { someTestFieldFunction(); log('whatHappensOnBlur(): OnBlur callback called: someTestFieldFunction()'); }, 50);
    log ('whatHappensOnBlur(): setTimeout for someTestFieldFunction() for 50ms');
}

function log(msg) {
    document.getElementById('log').value += ('[' + (new Date().getTime()).toString() + '] ' + msg + '\n');
}

function someTestFieldFunction() {
    log('someTestFieldFunction(): Inside someTestFieldFunction()');
    log('someTestFieldFunction(): Test: onClickFlag = ' + onClickFlag);
    //alert('you blurred the text field.');
    //alert('onClickFlag = ' + onClickFlag);
    setTimeout(enableButton, 50);
    log('someTestFieldFunction(): setTimeout for enableButton()');
}

function enableButton() {
    document.getElementById('theButton').disabled = false;
    log('enableButton(): Button re-enabled');
    //onClickFlag = false;
}

function whatHappensOnClick(el) {
    log('whatHappensOnClick(): the Button onClick fired');
    someFunction();
    log('whatHappensOnClick(): someFunction() called');
}

function whatHappensOnMouseDown(el) {
    log('whatHappensOnMouseDown(): inside whatHappensOnMouseDown()');
    onClickFlag = true;
    log("whatHappensOnMouseDown(): set onClickFlag = true");
}

function someFunction() {
    log('someFunction(): inside someFunction()');
    log('someFunction(): You have successfully clicked the button');
    //alert("you clicked me! this shouldn't happen!")
}

</script>
</head>
<body>
<form id="testform">
<input type="text" size="10" onfocus="whatHappensOnFocus(this);" onblur="whatHappensOnBlur(this);" />
<br />
<br />
<input id="theButton" type="button" onmousedown="whatHappensOnMouseDown(this);" onmouseout="onClickFlag = false;" value="calculate" onclick="whatHappensOnClick(this);" />
<br />
<br />
<textarea rows="15" cols="100" id="log" style="overflow: scroll"></textarea>
<input type="reset" value="clear" />
</form>
</body>
</html>

更新:

我更新了我发布的代码以反映一些问题,所以你可以看到我是如何测试这个的。当您将焦点放在文本字段上然后单击按钮时,该按钮的 onMouseDown 事件会在文本字段的 onBlur 事件之前触发。因此,我可以设置一个标志,以便我知道他们试图单击该按钮。然后在由文本字段的 onBlur 事件触发的 AJAX 调用的 onSuccess 回调事件中,我可以查看是否设置了按钮标志(所以我知道他们试图单击它)并触发该事件(禁用其他所有内容以便它可以完全的)。表单上只有几个按钮需要这种行为,所以我认为这个解决方案现在就足够了。

4

6 回答 6

4

你是AddEventListener用来设置事件的吗?如果是这样,你为第三个参数传递了什么?

这可能会有所帮助:

http://www.quirksmode.org/js/events_order.html

于 2009-07-22T14:23:37.990 回答
1

在完成所需的操作后,使用 js 导致文本框失去焦点怎么办?

于 2009-07-22T14:26:06.127 回答
0

最简单的方法(可能是最糟糕的,并且到目前为止)是让程序等待一段时间,然后再继续执行您希望它首先执行的操作,这样您就可以控制回调的顺序。

正如我所说,这可能是最糟糕的方法,但这是我能想到的唯一方法。这里应该是什么样子:

function onClickHandler(callback)
{
    setTimeout(callback, 50);
}

function onBlurHandler(callback)
{
    //...
}

这样,您在 onBlur 上的回调函数总是首先发生。

于 2009-07-22T14:16:10.497 回答
0

我怀疑事件的顺序是你问题的根源。我刚刚在 IE7、IE8 和 Chrome 中尝试了以下代码,事件的顺序总是模糊然后单击。

<script>
    function dbg(t) {
        document.getElementById("dbg").value += t + "\n";
    }
</script>
<input type="text" onblur="dbg('text.blur')" />
<input type="button" value="PressMe" onclick="dbg('button.click')" />
<textarea id="dbg" cols="50" rows="10">
</textarea>

如果我正确地跟随你,你正在做一些需要之前完成的其他调用的调用。这似乎不是一个很好的方法,使用这种方法您会遇到错误或代码的高度复杂性。

请尝试解释您的工作(从功能的角度)并尝试寻找替代方法,而不是尝试制定复杂的技术方法。

于 2009-07-22T14:27:48.450 回答
0

我假设您的点击事件依赖于模糊事件的结果。在这种情况下,我认为最好的办法是将按钮设置为禁用(或隐藏),然后在您的 onblur 请求完成时启用它。

<input type="submit" disabled="disabled" />

而伪Javascript...

onblur = function() {
  //ajax complete
  mybutton.disabled = false;   
}
于 2009-07-22T14:31:04.483 回答
0

固定超时 50 毫秒的问题是您依靠时间来解决问题。如果计算机由于某种原因运行缓慢,或者您正在运行速度较慢的上网本、旧计算机、旧浏览器或移动设备,该怎么办?也许您应该使用 setInterval 而不是 setTimer 并继续等待,直到您确认禁用确实发生了。

于 2009-07-22T18:00:55.067 回答