最近在做 zEditor 和 zReader 的时候,有一些小小的心得,在这里记录下。

现在本站用的编辑器,还是最原始的基于可编辑 div 的富文本编辑器,它有几个非常难于操作的地方,比如选区和光标,在各个浏览器下的 API 不尽相同。在看了 codecademy 的编辑器后得到启发,我也要做一个全部手动模拟输入的编辑器,于是开工了。

首先遇到的是输入法的问题,英文输入法还好,写一个字母,我就可以把这个字母从隐藏的 textarea 中获取然后填充到写作区,然后把这个 textarea 清空。但是中文输入法,在完成选字之前,textarea 中得到的还是字母和 '. 比如,我想打「前端」,在 textarea 中得到的结果是「qian’duan」。上面针对英文输入法的办法就行不通了。

在各种折腾之后发现:

chrome/IE9:

英文输入法,会依次触发 keydown keypress keyup 三个事件。
中文输入法,仅会触发 keydown keyup 两个事件,并且 keydown 的 keyCode 一直是 229, keyup 的时候才能获得正确的值。

FF:

英文输入法,会依次触发 keydown keypress keyup 三个事件。
中文输入法,只有按第一个字母的时候,会触发 keydown, 后面的输入将不再触发任何事件,除非做了终止输入的操作,比如,数字键、空格、enter. 这个时候仅会触发一次 keyup.

知道了上述浏览器的特性后,我们就可以模拟输入了。

针对中文输入:首先在 keydown 的时候捕获 keyCode, 如果值为 229, 则表示当前输入法为中文输入法,直至按了 enter 或者空格键或者数字键。按空格键或者数字键的时候,是正常的输入操作,只需要在 keydown 的时候检测输入法为中文输入法,并且在 keyup 的时候 keyCode 为空格键(32)或者数字键(也很难把握,一般情况下输入法会提供 1-5 的数字选择也就是 49-53), 这个时候就表示触发了输入操作。

针对英文输入:针对正常的英文输入操作,只需要检测 keypress 就可以了。有一点小技巧:在 keypress 的事件监听函数里面,直接获取按键的内容是获取不到的。需要加一个 setTimeout(fn, 0), 将获取内容的操作放到 fn 里面就能获取到了。

还有一种非正常的英文输入操作:在中文输入法下,按 enter 键。这种情况比较特殊。目前仅找到 chrome/IE9 下的解决方法:

在 keydown 的时候检测 keyCode, 若为229, 则设定一个定时器,在 keyup 中若键码不是 enter(13) 就清除它,再次 keydown 也会将它清除并重设。若定时器未被清除,则触发输入操作。

这样还存在一个问题,用户按住按键不放,这样只会触发 keydown, 经过大概 500ms 后会再次触发 keydown, 可这个时候定时器已经到了执行时间,执行了输入操作…所以需要加一个稍久一点的延时,我加了 510ms