7

给定 HTML:

<input type="text" id="test" />

和 JavaScript:

var $test = $('#test');

$test.on('keydown', function(event) {
    if (event.keyCode === 9) {
        $(event.target).val('change it!');
    }
});

$test.on('change', function(event) {
    alert('I am not called!');
});

如果我在输入中输入任何内容并点击tab,为什么change事件不会触发?事件keydown触发,并更新输入的值。

如果我删除.val()呼叫,那么change会触发。

起初,我认为这是一个 jQuery 问题(运行 1.9.1),但确认如果我使用纯 JavaScript 也会发生相同的行为。

4

3 回答 3

8

change仅对用户提交的更改触发。换句话说,使用 JavaScript 在后台更改元素的值不会触发change

Tab 实际上并没有改变元素的内容;它只是切换焦点。巧合的是,在某些方面,您正在键入 tab 来更改元素的内容(您不妨按下按钮来间接更新它,这也不会触发change)。

DOM 规范解释了为什么在您的特定情况下,如果您键入和制表符,用户输入将被丢弃并且不会触发任何更改。

具体来说:

对于任何给定的键,本规范中定义的键盘事件以相对于彼此的顺序发生:

  • 按键
  • keypress(仅适用于产生字符值的键)
  • 与此键相关的任何默认操作
  • 键位

当你按下tab键时,keydown被触发。繁荣,你的事件处理程序被调用!元素内容由您的脚本更新——没有触发更改,因为它是脚本执行的。用户贡献的内容被清除。现在是时候让浏览器执行与选项卡相关的默认操作了:移开焦点并查看元素是否被用户更改(触发 onchange)。不,它被剧本改变了!不change开火。

因此,如果您删除该val()行,您会注意到两件事。

  1. 如果您关闭元素焦点并关闭选项卡,change则不会触发 - 由于选项卡不会更改字段内容,因此没有发生任何更改。
  2. 如果您给元素焦点并键入某些内容并关闭选项卡,change则会触发,因为在那个神奇的“与选项卡相关的默认操作”时刻,浏览器会注意到用户做出了更改。

哇!

于 2013-09-17T19:54:10.803 回答
2

我从来没有弄清楚原因(正如其他响应者已经做过的那样),但我确实为您找到了解决方案,因为您已经在使用 jQuery。只需使用其 jQuery 方法而不是 val() 自己触发更改事件:

var test = $('#test');
test.on('keydown', function(event) {
if (event.keyCode == 9) {
    $(event.target).change(function(){
        this.value = 'change it!';
    });
}
});
test.on('change', function(event) {
    alert('I am not called!');
});

小提琴

于 2013-09-17T20:05:06.863 回答
1

您正在更改keyup选项卡之前的值。在keyup更改事件将被触发。但是由于您在处理程序期间更改了值keydown,所以当它失去焦点时,值会恢复到以前的值。

要看到这一点,请将您的 jquery 从keydownto更改为keyup,您将看到事件触发(您还将看到事件触发,然后keyup触发并更改文本)。

于 2013-09-17T19:57:19.997 回答