如何在警告框(alert)后给予焦点(focus())?

11

我有一个类似这样的东西:

<input type="textbox" id="partNumber" onChange="validatePart(this);">
<input type="textbox" id="quantity" onfocus="saveOldQuantity(this);">
onChange事件在更改完成并且文本框失去焦点后正确触发。当quantity获得焦点时,onfocus事件会正确触发以保存quantity的旧值,在进行更改之前。
如果validatePart()检测到无效的partNumber值,则会向用户发出alert。在alert()清除后,我想将焦点返回到partNumber输入框。但是在输入节点上执行focus()不会使其获得焦点。在这里进行调试很棘手,因为IE调试窗口的交互当然会改变焦点。
如何确保在validatePart()中检测到错误时焦点返回到partNumber
编辑: validatePart()的简单版本:
function validatePart(node) {
    if (!node.value) {
        alert('Please enter a part number.');
        node.focus();   // <======= why isn't this having any effect??
    }
}

2
在设置焦点之前,您可以尝试一下小的超时时间吗? - pimvdb
并不是屏幕冻结了。焦点会跳转到用户点击或切换的位置。我需要以某种方式取消该操作并覆盖它,将焦点返回到“partNumber”。 - Jonathan M
我不确定是否可以防止用户选择另一个选项卡。个人而言,我也不喜欢这样做。 - pimvdb
@pimvdb:也许不是取消,而更像是当您加载页面并使用node.focus();聚焦节点时的情况。由于某种原因,此处focus()方法无法正常工作。 - Jonathan M
1
我曾经遇到过一些专注方面的问题,所以有时候暂停一下会有所帮助。例如,请尝试 setTimeout(function() { node.focus(); }, 500); - pimvdb
显示剩余2条评论
2个回答

20

添加一个小的超时时间并将焦点重置到partNumber文本框,就能解决问题。

因此,您的validatePart()函数变成了这样:

function validatePart(node) {
    if (!node.value) {
        alert('Please enter a part number.');
        setTimeout(function(){node.focus();}, 1);
    }
}

这里是一个快速的“实时”示例,它会触发一个 alert,无论在 partNumber 文本框中输入的是什么内容,并成功将焦点返回到 partNumber 文本框 (即使您按 Tab 键切换到 quantity 文本框)。


1
不要将字符串传递给 setTimeout(它会被 eval),应该传递一个函数。setTimeout(function(){document.getElementById("partNumber").focus();}, 1); - gen_Eric
@Rocket - 你说得对。我已经修改了我的答案,以反映更加技术上正确的版本,通过将一个函数传递给setTimeout函数,而不是需要在执行之前进行eval的字符串。 - CraigTP
@CraigTP:对我来说,1毫秒的超时时间很有效。顺便说一句,我只是使用了一个通用的function()作为第一个参数。谢谢! - Jonathan M
使用 setTimeout(function(){document.getElementById(node.id).focus();}, 1); 对我很有用。没有 document.getElementById 就无法正常工作。 - Sacky San

2
您的代码对我来说似乎按预期工作。请参见此示例。您是否看到其他行为?我注意到我在文本框1中键入一个数字。然后当我切换到文本框2时,我会收到“无效零件!”错误并保持焦点在当前文本框上。
更新-由于这只在Chrome中有效,因此您可以跟踪错误是否存在。如果是,则处理它。
var error = null;
function checkForErrors() { 
   if (error) { error.focus(); error = null; }            
}

function validatePart(node) {
   if (badpart) { error = node; }
}

function saveOldQuantity(node) {
   checkForErrors();
}

好的,看起来在IE9或FF中不起作用。在Chrome中运行良好。我会再仔细看看。 - mrtsherman
@Jonathan M - 我更新了我的答案,提供了一种非settimeout的解决方案。我总是尽力避免使用它们。我希望它能像 node.focus() 一样优雅,但事件的处理顺序不对,所以不能那么简单。 - mrtsherman
但是如果事件的顺序很重要,saveOldQuantity在调用checkForErrors之前,validatePart有机会分配error吗? - Jonathan M
事件的顺序是一个问题,从validatePart中调用.focus()。现在我将该调用移到saveOldQuantity的focus中。因此,事件的顺序已经解决。 - mrtsherman
啊,是的。我明白了。唯一让我不采用这种方法的是使用全局变量 (error)。但是,我绝对喜欢非时间依赖的方法。点个赞。 :) - Jonathan M

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