为什么使用 .focus() 时我的 onchange 函数被调用两次?

发布于 2024-10-19 21:45:24 字数 1606 浏览 6 评论 0原文

TLDR

  • 在 Chrome 中查看此示例
  • 输入一些内容并按 tab。看到一个新框出现,
  • 输入一些内容并按 enter。看到出现了两个新框,其中出现了一个预期的框。

简介
我注意到,当使用 enter 而不是 tab 来更改字段时,输入字段上的 onchange 函数会触发两次。这个页面相当大,并且仍在开发中(阅读:许多其他错误),因此我制作了一个最小的示例来显示此行为,在这种情况下,它甚至在“选项卡”上执行此操作。据我所知,这只是 Chrome 中的一个问题。

它应该做什么
我想在输入字段中输入某些内容后进行新的输入。这个领域应该受到关注。

示例:

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 部分

<div>
    <input type="text" onchange="return myOnChange(this,1);" id="prefix_1">
</div>

完整的代码位于 pastebin 。您需要在脚本中添加 jquery 的路径

一个工作示例位于 jFiddle

onchange 被调用两次:调用 myOnChange 函数,创建新输入,调用 focus(),再次调用 myOnChange,进行新输入,“内部”myOnChange 退出,然后“外部”myOnchange 退出。

我假设这是因为焦点更改触发了 onchange()?。我知道浏览器之间的行为存在一些差异。

我想停止 .focus() (这似乎是问题)而不调用 onchange(),因此 myOnChange() 不会被调用两次。有人知道怎么做吗?

TLDR

  • Check this example in 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.

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 Chrome as far as I can tell.

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

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

<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

A working example is here on 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.

I'm assuming this is because the focus change fires the onchange()?. I know there is some difference in behaviour between browsers in this.

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

苏佲洛 2024-10-26 21:45:24

有一种更简单、更合理的解决方案。正如您期望 onchange 在输入值更改时触发一样,您可以简单地显式检查它是否确实发生了更改。

function onChangeHandler(e){
  if(this.value==this.oldvalue)return; //not changed really
  this.oldvalue=this.value;
  // .... your stuff
}

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.

function onChangeHandler(e){
  if(this.value==this.oldvalue)return; //not changed really
  this.oldvalue=this.value;
  // .... your stuff
}
得不到的就毁灭 2024-10-26 21:45:24

快速修复(未经测试)应该是将对 focus() 的调用推迟

setTimeout(function() { ... }, 0);

到事件处理程序终止后。

然而,无需这样的黑客攻击也可以使其正常工作。无 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>

A quick fix (untested) should be to defer the call to focus() via

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:

<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>
山川志 2024-10-26 21:45:24

我可以确认 myOnChange 在 Chrome 上被调用了两次。但 context 参数是两次调用的初始输入字段。

如果您删除警报调用,它只会触发一次。如果您仅使用警报进行测试,请尝试使用控制台(尽管您需要将其删除以在 IE 中进行测试)。

编辑: 似乎更改事件在输入键。以下添加了一个条件来检查新字段是否存在。

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;
}

更新:

$('#prefix_'+nextNum).focus(); 不会被调用,因为 focus 是 dom 对象的方法,而不是 jQuery。使用 $('#prefix_'+nextNum)[0].focus(); 修复了该问题。

I can confirm myOnChange gets called twice on Chrome. But the context argument is the initial input field on both calls.

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).

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();.

兔小萌 2024-10-26 21:45:24

问题确实是因为focus(),onchange被再次调用。我不知道这是否是一个好的解决方案,但是将其添加到函数中是一个快速的解决方案:(

context.onchange = "";

再次调用 onchange,但现在是空的。这也很好,因为这个函数永远不应该被调用两次。有最终产品中将进行一些界面更改,以帮助解决由此产生的问题(错误和所有),但最终这可能是我无论如何都会做的事情)。

解决方案在这里: http://jsfiddle.net/k4WKH/2/

正如@johnhunter所说,焦点在示例中不起作用,但在我的完整代码中起作用。我还没有研究过那里发生了什么,但这似乎是一个单独的问题。

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:

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).

sollution here: 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.

口干舌燥 2024-10-26 21:45:24

也许这对任何人都有帮助,无论出于何种原因,在chrome中,当您将事件onchage附加到输入文本时,当您按下回车键时,事件中的函数,执行两次,我解决了这个问题,将事件更改为onkeypress并且评估代码,如果我有回车键,则执行该功能,因为我只等待用户的回车键,这不适用于 Tab 键。

    input_txt.onkeypress=function(evt){ 
            evt = evt || window.event;
            var charCode = evt.which || evt.keyCode;
            if(charCode === 13)  evaluate( n_rows ); 
             };

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.

    input_txt.onkeypress=function(evt){ 
            evt = evt || window.event;
            var charCode = evt.which || evt.keyCode;
            if(charCode === 13)  evaluate( n_rows ); 
             };
红焚 2024-10-26 21:45:24

试试这个例子:

var curNum = 1;
function myOnChange( context )
{
    curNum++;

    $('<input type="text" onchange="return myOnChange( this )" id="prefix_'+ curNum +'" >').insertAfter( context );
    $('#prefix_'+ curNum ).focus();

    return false;
}

jsFiddle

Try this example:

var curNum = 1;
function myOnChange( context )
{
    curNum++;

    $('<input type="text" onchange="return myOnChange( this )" id="prefix_'+ curNum +'" >').insertAfter( context );
    $('#prefix_'+ curNum ).focus();

    return false;
}

jsFiddle.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文