因此,我当前的项目还有另一个小的 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 回调事件中,我可以查看是否设置了按钮标志(所以我知道他们试图单击它)并触发该事件(禁用其他所有内容以便它可以完全的)。表单上只有几个按钮需要这种行为,所以我认为这个解决方案现在就足够了。