上下文:
我有一张表格,要求提供邮政编码、州和城市。在每个输入字段旁边有两个跨度,如果输入良好,一个会显示绿色复选标记,如果输入错误,一个会显示红色 x。当然,在任何给定时间只有一个可见。
<input type="text" id="Zip" class="form-control">
<span id="ZipOK" style="display:none;" class="glyphicon glyphicon-ok"></span>
<span id="ZipBad" style="display:none;" class="glyphicon glyphicon-remove"></span>
<input type="text" id="State">
<span id="StateOK" style="display:none;" class="glyphicon glyphicon-ok"></span>
<span id="StateBad" style="display:none;" class="glyphicon glyphicon-remove"></span>
<input type="text" id="City">
<span id="CityOK" style="display:none;" class="glyphicon glyphicon-ok"></span>
<span id="CityBad" style="display:none;" class="glyphicon glyphicon-remove"></span>
我有一个函数可以检测邮政编码字段的输入,然后执行数据库调用以从邮政编码获取州和城市并自动填写表单。
jQuery('.form-control').keyup(function(){
validateZipcode();
});
这是执行 ajax、自动填充州/城市并隐藏/显示适当的反馈范围的函数。
function validateZip() {
zip = $('#Zip').val();
if (zip.length === 5 && $.isNumeric(zip)) {
$.ajax({
type:"POST",
url: '?report=ajax&request=getStateAndCityFromZip',
data:"Zip="+encodeURIComponent(zip),
success: function(output) {
output = $.parseJSON(output);
if (output['State'].length > 0 && output['City'].length > 0) {
$('#State').val(output['State']);
$('#City').val(output['City']);
$('#StateOK').fadeIn();
$('#StateBad').hide();
$('#CityOK').fadeIn();
$('#CityBad').hide();
$('#ZipOK').fadeIn();
$('#ZipBad').hide();
} else {
$('#ZipOK').hide();
$('#ZipBad').fadeIn();
}
},
error: function (xhr, ajaxOptions, thrownError) {
}});
} else {
$('#ZipOK').hide();
$('#ZipBad').fadeIn();
}
}
问题:
此代码按原样工作,但是在某些情况下,如果我极快地输入邮政编码,#ZipBad
和 #ZipGood
范围都会结束可见的。以相对正常或较慢的速度打字会产生预期的行为。
我认为这与异步调用 validateZip() 有关,但我对 javascript 的了解还不够,不知道如何解决这个问题。有人有什么想法吗?
最佳答案
如果用户打字速度很快,那么您可能会同时处理多个动画,并且不是动画的 .hide()
将以错误的顺序运行,可能会结束显示错误。动画按顺序排列,.hide()
则不然,因此事情可能会乱序。
还有一些边缘情况,您最终可能会同时进行多个 ajax 调用,但这需要在 zip 字段中输入 5 个字符,然后快速退格并再次输入第五个字符,这可能会结束也搞乱了事情。
您可以在每次动画或可见性更改之前使用 .stop(true)
来防御动画,以停止任何当前正在运行的动画,并且您可以通过取消任何先前的调用来防御多个 ajax 调用,例如这个:
这是实现此目的的一种方法:
var lastValidateAjax;
function validateZip() {
var zip = $('#Zip').val();
if (zip.length === 5 && $.isNumeric(zip)) {
if (lastValidateAjax) {
lastValidateAjax.abort();
}
lastValidateAjax = $.ajax({
type:"POST",
url: '?report=ajax&request=getStateAndCityFromZip',
data: {Zip: zip},
success: function(output) {
lastValidateAjax = null;
output = $.parseJSON(output);
if (output.State.length > 0 && output.City.length > 0) {
$('#State').val(output.State);
$('#City').val(output.City);
$('#StateOK, #CityOK, #ZipOK').stop(true).fadeIn();
$('#StateBad, #CityBad, #ZipBad').stop(true).hide();
} else {
$('#ZipOK').stop(true).hide();
$('#ZipBad').stop(true).fadeIn();
}
},
error: function (xhr, ajaxOptions, thrownError) {
lastValidateAjax = null;
}
});
} else {
$('#ZipOK').stop(true).hide();
$('#ZipBad').stop(true).fadeIn();
}
}
仅供引用,我还借此机会在同一个选择中使用多个项目,并使用 jQuery 链接来简化代码。
请参阅另一个答案,了解 jQuery 用于 ajax 调用的 .abort()
的讨论:
关于JavaScript 对更新 DOM 元素的函数的异步调用重叠并导致问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30857059/