Javascript 为什么在使用 .focus() 时我的 onchange 函数会被调用两次?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5166086/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is my onchange function called twice when using .focus()?
提问by Nanne
TLDR
TLDR
- Check this examplein chrome.
- Type someting and press
tab
. see one new box appear - type something and press
enter
. see two new boxes appear, where one is expected.
- 在 chrome 中检查这个例子。
- 键入一些内容并按
tab
。看到一个新框出现 - 键入内容并按
enter
。看到两个新框出现,其中一个是预期的。
Intro
I noticed that when using enter
rather then tab
to change fields, my onchange function on an input field was firing twice. This page was rather large, and still in development (read: numerous other bugs), so I've made a minimal example that shows this behaviour, and in this case it even does it on 'tab'. This is only a problem in Chromeas far as I can tell.
介绍
我注意到,当使用enter
而不是tab
更改字段时,我在输入字段上的 onchange 函数触发了两次。这个页面相当大,并且仍在开发中(阅读:许多其他错误),所以我做了一个显示这种行为的最小示例,在这种情况下它甚至在“选项卡”上进行。据我所知,这只是Chrome 中的一个问题。
What it should do
I want to make a new input after something is entered into the input-field. This field should get focus.
它应该做什么
我想在输入字段中输入内容后进行新输入。这个领域应该得到关注。
Example:
例子:
javascript - needing jquery
javascript - 需要 jquery
function myOnChange(context,curNum){
alert('onchange start');
nextNum = curNum+1;
$(context.parentNode).append('<input type="text" onchange="return myOnChange(this,'+nextNum+')" id="prefix_'+nextNum+'" >');
$('#prefix_'+nextNum).focus();
return false;
}
HTML-part
HTML 部分
<div>
<input type="text" onchange="return myOnChange(this,1);" id="prefix_1">
</div>
the complete code is on pastebin. you need to add your path to jquery in the script
完整的代码在 pastebin 上。您需要在脚本中添加 jquery 的路径
A working example is here on jFiddle
jFiddle上有一个工作示例
The onchange gets called twice: The myOnChange
function is called, makes the new input, calls the focus()
, the myOnChange
gets called again, makes a new input, the 'inner' myOnChange
exits and then the 'outer' myOnchange
exits.
onchange 被调用两次:调用myOnChange
函数,生成新输入,调用focus()
,myOnChange
再次调用,生成新输入,“内部”myOnChange
退出,然后“外部”myOnchange
退出。
I'm assuming this is because the focus change fires the onchange()
?. I know there is some difference in behaviour between browsers in this.
我假设这是因为焦点变化会触发onchange()
?。我知道在这方面浏览器之间的行为存在一些差异。
I would like to stop the .focus() (which seems to be the problem) to NOT call the onchange()
, so myOnChange()
doesn't get called twice. Anybody know how?
我想停止 .focus() (这似乎是问题)不调用onchange()
,所以myOnChange()
不会被调用两次。有人知道怎么做吗?
采纳答案by Christoph
A quick fix (untested) should be to defer the call to focus()
via
一个快速修复(未经测试)应该是推迟调用focus()
通过
setTimeout(function() { ... }, 0);
until after the event handler has terminated.
直到事件处理程序终止之后。
However, it is possible to make it work without such a hack; jQuery-free example code:
但是,可以在没有这种 hack 的情况下使其工作;无 jQuery 示例代码:
<head>
<style>
input { display: block; }
</style>
<body>
<div></div>
<script>
var div = document.getElementsByTagName('div')[0];
var field = document.createElement('input');
field.type = 'text';
field.onchange = function() {
// only add a new field on change of last field
if(this.num === div.getElementsByTagName('input').length)
div.appendChild(createField(this.num + 1));
this.nextSibling.focus();
};
function createField(num) {
var clone = field.cloneNode(false);
clone.num = num;
clone.onchange = field.onchange;
return clone;
}
div.appendChild(createField(1));
</script>
回答by jooher
There's a way easier and more reasonable solution. As you expect onchange fire when the input value changes, you can simply explicitly check, if it was actually changed.
有一种更简单、更合理的解决方案。正如您期望在输入值更改时触发 onchange 一样,您可以简单地明确检查它是否确实已更改。
function onChangeHandler(e){
if(this.value==this.oldvalue)return; //not changed really
this.oldvalue=this.value;
// .... your stuff
}
回答by johnhunter
I can confirm myOnChange
gets called twice on Chrome. But the context
argument is the initial input field on both calls.
我可以确认myOnChange
在 Chrome 上被调用了两次。但context
参数是两个调用的初始输入字段。
If you remove the alert call it only fires once. If you are using the alert for testing only then try using console instead (although you need to remove it for testing in IE).
如果您删除警报调用,它只会触发一次。如果您仅使用警报进行测试,请尝试使用控制台(尽管您需要将其删除以在 IE 中进行测试)。
EDIT:It seems that the change event fires twice on the enter key. The following adds a condition to check for the existence of the new field.
编辑:似乎更改事件在回车键上触发了两次。下面添加一个条件来检查新字段是否存在。
function myOnChange(context, curNum) {
nextNum = curNum+1;
if ($('#prefix_'+nextNum).length) return false;// added to avoid duplication
$(context.parentNode).append('<input type="text" onchange="return myOnChange(this,'+nextNum+')" id="prefix_'+nextNum+'" >');
$('#prefix_'+nextNum)[0].focus();
return false;
}
Update:
更新:
The $('#prefix_'+nextNum).focus();
does not get called because focus is a method of the dom object, not jQuery. Fixed it with $('#prefix_'+nextNum)[0].focus();
.
该$('#prefix_'+nextNum).focus();
不会被调用,因为重点是DOM对象,而不是jQuery的方法。用 修复它$('#prefix_'+nextNum)[0].focus();
。
回答by saheka
maybe this some help to anybody, for any reason, in chrome when you attach an event onchage to a input text, when you press the enterkey, the function in the event, do it twice, i solve this problem chaged the event for onkeypress and evaluate the codes, if i have an enter then do the function, cause i only wait for an enterkey user's, that not works for tab key.
也许这对任何人都有帮助,无论出于何种原因,在 chrome 中,当您将事件 onchage 附加到输入文本时,当您按下 enterkey 时,事件中的函数,执行两次,我解决了这个问题,因为 onkeypress 和评估代码,如果我有输入然后执行该功能,因为我只等待输入用户的输入,这不适用于 Tab 键。
input_txt.onkeypress=function(evt){
evt = evt || window.event;
var charCode = evt.which || evt.keyCode;
if(charCode === 13) evaluate( n_rows );
};
回答by Nanne
The problem is indeed that because of the focus()
, the onchange is called again. I don't know if this is a good sollution, but this adding this to the function is a quick sollution:
问题确实是因为focus()
, onchange 再次被调用。我不知道这是否是一个好的解决方案,但是将它添加到函数中是一个快速的解决方案:
context.onchange = "";
(The onchange is called again, but is now empty. This is also good because this function should never be called twice. There will be some interface changes in the final product that help with problems that would arise from this (mistakes and all), but in the end this is something I probably would have done anyway).
(onchange 再次被调用,但现在是空的。这也很好,因为这个函数不应该被调用两次。最终产品中会有一些界面变化,以帮助解决由此产生的问题(错误和所有),但最终这是我可能会做的事情)。
sollution here: http://jsfiddle.net/k4WKH/2/
这里的解决方案:http: //jsfiddle.net/k4WKH/2/
As @johnhunter says, the focus does not work in the example, but it does in my complete code. I haven't looked into what's going on there, but that seems to be a separate problem.
正如@johnhunter 所说,焦点在示例中不起作用,但在我的完整代码中起作用。我还没有研究那里发生了什么,但这似乎是一个单独的问题。