在某些情况下,比如自动补全(auto complete)的输入框中,需要使用keyup事件来监听键盘的输入以迅速作出回应。
关键在于keyup, 如果世界是美好的,那么就不会有这篇blog. 可是……
世界是不美好的。我们活在中文世界,我们要用输入法。在输入法开启的情况下,您会碰到不美好的事情:keyup失效。对于您绑定到keyup的任何回调函数,除非您把输入法切换回英文状态,否则它会无动于衷。如果能称之为bug,我会很高兴,因为bug会有修复的可能,如果是特征(feature),那么,我只好叹息一下。
问题
在开启输入法的情况下,三个浏览器的具体问题如下:
- IE:触发keydown和keyup, 不触发keypress. 能够获得输入值。
- Firefox:触发keydown和keypress, 不触发keyup. 输入值未能获得。在回车后会触发keyup, 可获得输入值。
- Opera:keydown, keypress和keyup都不触发,输入值也未能获。
(如果您能帮我试用一下Safari,我会很高兴并谢谢您。这里有一个测试页面:http://tonextone.com/test/eventTest.html)
解决方案
总结出以上问题,没有兴奋反而陷入绝望,因为没有google出解决方案(是的,对于拉丁语系的老外来说,不会存在输入法)。但是,wait, 谷歌搜索的自动补全不是工作得好好的吗?于是研究一下这个 http://www.google.cn/ac.js。嘿嘿,虽然混淆得还可以,但还是可以发现蛛丝马脚的。它使用一个计时器,当输入框处于聚焦(focus)状态时,每 10 毫秒执行一次回调函数。
虽然挺耗资源(所以建议在输入框失焦(blur)时,一定要清除这个计时器),但也只能如此了。作前端开发的,不仅要与语言(JavaScript, CSS, HTML) 斗,还要与浏览器斗,其乐无穷也。
更新:IE 有一个 onpropertychange 事件处理器可以随时检测变化,对应之,Firefox 和 Opera 有一个 oninput 事件处理器也可以达到目的。遗憾的是,在输入法开启的情况下,Opera对于 oninput 也没法随时监听(表现在:输入英文字母可以监听到,而中文则失效)。如果不考虑 Opera, IE使用 onpropertychange 而 Firefox 使用 oninput, 也可解决我们上述问题。
另外需要注意的是, oninput 比较诡异,您可以<input oninput="jsFunc()" ... />来绑定,也可以用addEventListener来绑定,就是不能使用 DOM 0 的element.oninput = function(){} 的形式来绑定,否则不生效。
未曾测试Safari, 有心者可自行测试之。
October 31st, 2007
by terababy
终于能够感觉到做网站和企业应用如何不同了。做企业应用只要做IE就可以了,因为可以要求用户统一用IE。所以虽然貌似这种问题过去遇到过也都轻轻飘过了。
October 31st, 2007
by sixfooter
safari
我试过了
可以获得值.
October 31st, 2007
by aoao
我猜这篇一定是跟微软拼音有关。=。=
其实我以前也撞到过。。。。。。
对了。我换域名了。下面改改地址。
October 31st, 2007
by kakawar
感谢你的分享。
我们最近做的一个网站,登陆框不知怎么回事,按回车键无法提交。所以我想写个函数,在输入框获得焦点的时候,用keypress模拟提交事件。
请教一下,怎样判断一个输入框处于聚焦状态呢?我没有查到专门的属性。现在打算在输入框onfocus的时候绑定一个函数,onblur的时候取消它,这样做是不是太笨了呢……
October 31st, 2007
by Cloudream
Safari出发down和up,但只有keyup正确找到输入内容
keyDown:å(229) :
keyPress:(0) :
keyUp:A(65) :
keyDown:å(229) :
keyPress:(0) :
keyUp:D(68) :
keyDown:å(229) :
keyPress:(0) :
keyUp:F(70) :
keyDown:å(229) :
keyPress:(0) :
keyUp:E(69) :
October 31st, 2007
by Bonede
还是比较偏向使用计时器。
用事件感觉有点怪。
October 31st, 2007
by realazy
The Author
@aoao
貌似只有一些不常用的输入法比如陈桥五笔(未测试)之类才没有问题。
@kakawar
只能是这么做。不过可以先把主要的函数写好,onfocus/onblur只是作为一个计时器开关而已。
@Cloudream
非常感谢。
@Bonede
从理论上说,应该是监听事件比较合适。但是既然有问题,那么只好用计时器了。这属于trick了。
November 2nd, 2007
by Gawain
我在safari下使用,OpenVanilla+自己的五笔码表,没有问题
keyDown:K(75) :
keyUp:K(75) : 口
keyDown:W(87) : 口
keyUp:W(87) : 口人
keyDown:G(71) : 口人
keyUp:G(71) : 口人王
keyDown: (32) : 口人王
keyUp: (32) : 哈
keyDown:K(75) : 哈
keyUp:K(75) : 哈口
keyDown:W(87) : 哈口
keyUp:W(87) : 哈口人
keyDown:G(71) : 哈口人
keyUp:G(71) : 哈口人王
keyDown: (32) : 哈口人王
keyUp: (32) : 哈哈
onChange:哈哈
November 2nd, 2007
by aw
1、与浏览器斗
2、与输入法斗
3、与变态用户斗
November 4th, 2007
by safe6
感谢你的分享。
学习了,支持一下。
November 5th, 2007
by 哉崽
最近也写了一个自动完成的JS,因为是针对英文查询绑定动作的,所以没碰到过输入法问题,看来等以后扩展中文输入的时候,问题就明显起来了,呵呵
淘宝上不是也有一个类似的自动提示吗?不知道啥方法来绕过解决这个问题,有空去研究下,嘿嘿
November 8th, 2007
by jjgod
Safari works fine.
November 13th, 2007
by March
虽然和输入法没多少关系,但是对键盘事件的讲解很详细:
http://unixpapa.com/js/key.html
November 14th, 2007
by sea
FF2.0下使用测试:
keyDown:(17) :
keyUp: (32) :
keyUp:(17) : keyDown:å(229) :
keyPress:å(229) :
keyUp: (32) : 你keyDown:å(229) : 你
keyPress:å(229) : 你
keyUp: (32) : 你好
IE6.0-SP2下测试:
keyDown:(17) :
keyUp: (32) :
keyUp:(17) :
——————————————————————————–
keyDown:å(229) :
keyUp:W(87) :
——————————————————————————–
keyDown:å(229) :
keyUp:Q(81) :
——————————————————————————–
keyDown:å(229) :
keyUp: (32) : 你
——————————————————————————–
keyDown:å(229) : 你
keyUp:V(86) : 你
——————————————————————————–
keyDown:å(229) : 你
keyUp:B(66) : 你
——————————————————————————–
keyDown:å(229) : 你
keyUp: (32) : 你好
——————————————————————————–
onChange:你好
January 15th, 2008
by Leon
快被这个问题弄晕了。最后非ie下设了一个计时器检测value,ie下用onkeyup解决的
April 12th, 2008
by lone
能up就up,赫赫
May 4th, 2008
by s79
“每10秒执行一次回调函数。”
应该是每10毫秒,10秒太长了。
July 5th, 2008
by 李福拉
onpropertychange别乱用啊…对象任何一个属性值变更了都会触发..包括样式….
August 2nd, 2008
by yzx99
谢谢!
August 26th, 2008
by 当键盘事件遇上输入法 - 浅析谷歌的一个Bug - 岁月如歌
[...] Realazy的探索:http://realazy.org/blog/2007/10/31/solution-of-keyup-failing-when-ime-is-on/ [...]
May 20th, 2009
by jlake
用 jQuery 可解决:
$(’:text’).bind(’text’, function () {console.log($(this).val()});
May 21st, 2009
by jlake
更正:
var logFunc = function(){console.log($(this).val())};
$(’:text’).keyup(logFunc).bind(’text’, logFunc);