【问题标题】:Why is my onchange function called twice when using .focus()?为什么在使用 .focus() 时我的 onchange 函数会被调用两次?
【发布时间】:2011-03-02 10:24:52
【问题描述】:

TLDR

  • 在 chrome 中检查此 example
  • 键入 someting 并按 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>

完整的代码是on pastebin。你需要在脚本中添加你的 jquery 路径

jFiddle 上有一个工作示例

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

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

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

【问题讨论】:

    标签: javascript jquery google-chrome focus onchange


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      一个快速修复(未经测试)应该是通过推迟调用focus()

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

      直到事件处理程序终止。

      但是,没有这样的 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>
      

      【讨论】:

      • 看起来是个不错的方法,但由于我可能需要使用“remove onchange” hack,所以我认为我会使用它。快速测试似乎确实表明这是可行的,+1 :)
      • 注意:我没有使用过这种方法,但它看起来是这个问题的最佳答案。我的问题还有一些问题,所以我使用了我在下面提供的答案,但仍然将此标记为已接受;)
      【解决方案3】:

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

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

      编辑: 似乎 change 事件在 enter 键上触发了两次。下面添加一个条件来检查新字段是否存在。

      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(); 不会被调用,因为焦点是 dom 对象的方法,而不是 jQuery。用$('#prefix_'+nextNum)[0].focus(); 修复它。

      【讨论】:

      • 该警报确实仅用于测试:)。我已将其删除,但不幸的是,这仍然是一个双重调用。
      • 啊,是的。我在打标签。我在输入时得到双倍。
      • 我添加了一个 jsFiddle 示例
      • +1 寻求焦点问题的帮助。我将使用我想出的解决方案,但这很有帮助:)
      【解决方案4】:

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

      context.onchange = "";
      

      (再次调用 onchange,但现在是空的。这也很好,因为这个函数永远不应该被调用两次。最终产品中会有一些接口更改,以帮助解决由此产生的问题(错误和全部),但最后我可能还是会这样做)。

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

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

      【讨论】:

        【解决方案5】:

        也许这对任何人都有帮助,无论出于何种原因,在 Chrome 中,当您将事件 onchage 附加到输入文本时,当您按下回车键时,事件中的功能,执行两次,我解决了这个问题 chaged 事件对于 onkeypress 和评估代码,如果我有一个 enter 然后执行该功能,因为我只等待一个 enterkey 用户,这不适用于 tab 键。

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

        【讨论】:

          【解决方案6】:

          试试这个例子:

          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.

          【讨论】:

          • 这仍然会在 enter 上创建两个文本框
          • 对不起,这确实在输入时创建了 2 个新字段 :(
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-12-31
          • 1970-01-01
          • 1970-01-01
          • 2013-01-12
          • 2021-11-06
          • 1970-01-01
          相关资源
          最近更新 更多