写点什么

Web 键盘输入法应用开发指南 (5) —— 实战技巧

作者:天择
  • 2022 年 3 月 04 日
  • 本文字数:2924 字

    阅读完需:约 10 分钟

Web 键盘输入法应用开发指南 (5) —— 实战技巧

引言

在这篇文章中,我会分享一些在实际项目中遇到的问题以及常用实践供大家参考,避免踩坑。多踩坑虽然能积累经验,但也会浪费时间。与键盘和输入法相关的 Web 应用常常要处理平台兼容性的问题,开发者不仅要通过各种设备覆盖各个浏览器的实现,还要测试各种用户输入的场景以保证没有遗漏边缘 case。其实,这类应用程序往往是通过修修补补的方式逐步完善的。本文可以在这方面提供一些参考,希望能帮助相关开发者少走弯路。

不要依赖某一种事件

从前面几篇文章可以看出,浏览器提供的、处理与用户输入相关的事件实在不少,如 keydown/keypress、input 以及 composition 等等。开发者不仅需要了解每种事件的定义和包含的信息,还要掌握各类事件触发的场景有时并不产生 composition*事件,而是使用input事件。这里的“有时”通常是指输入特殊符号,如中文的等。


这里的例子是要提醒我们,不要依赖单一的事件。虽然 composition 相关事件天然是为了输入法而设计,但并不意味着所有浏览器都会触发。同理,keypress 事件也经常被用来处理符号的输入,但也不保证一定存在。脑子里时刻绷着这根弦,可以避免许多因为测试不到位而暴露的严重 bug(用户完全无法输入了)!

多与原生 HTML 页面对比

这其实是一个开发技巧。有些时候业务要求要开发者自己控制输入的过程,而非直接使用输入法软件与浏览器交互后的输入结果,比如想在根据用户输入的过程实现一些业务逻辑。如果我们对某些语言(日语、韩语)不熟悉,就不知道自己是否正确实现。这时可以另写一个简单的 HTML 页面,创建一个输入控件,绑定相关事件,然后对比直接在原生 Web 页面的输入结果。


这个方法也适用于对某些事件是否触发不太确定的场景。由于业务逻辑代码比较复杂,我们可能不好判断某个事件没有捕获到,是平台兼容性问题,还是自己实现的问题,这时一个简单的页面可能会告诉你答案。

谨慎阻止事件

阻止事件传播主要涉及两个 API:preventDefault[1]和stopPropagation[2]。使用preventDefault可以取消一个事件默认的效果,但不会阻断事件的传播。比如你想阻止某个键的输入,可以先绑定keydown事件,然后根据key属性进行处理:


const textInput = document.getElementById('my-text');textInput.addEventListener('keydown', validate, false);
function validate(evt) { let key = evt.key; if (key === 'a' || key === 'A') { evt.preventDefault(); console.warn("You are not allowed to input letter 'A'."); }}
复制代码


这里如果遇到字母 A 键被按下,事件的默认行为被取消(cancelled),该键就无法输入了。与此对应,stopPropagation会阻止事件的捕获和冒泡过程,而不会取消事件的默认行为和效果。有关这两个 API 的详细用法可查阅相关文档,这里不细说。


需要注意的是,无论是取消事件效果还是阻断事件传播,都可能带来副作用,我们在使用时需要小心。比如,开发者在移动设备上取消了 touch 事件的效果,而是自行处理后续的逻辑,那么可能对一些输入场景产生影响。我之前在写与韩语输入法的相关程序时,踩过这类坑。


在采用韩语输入的过程中,你的设备上软键盘的输入法会有一个输入的中间状态,接下来的输入或者删除操作都与之前输过的字符相关,直到你按了回车、空格键或者单击了屏幕其他位置(触发 touch 事件),取消这个输入状态。问题来了,如果 touch 事件的效果被取消了,本来应该取消韩语输入法状态的效果没了,那么你后续的输入还是基于原来的输入状态,这就与预期不符了。感兴趣的话可以在自己的手机上试一下。


阻断事件传播也有风险,因为页面上可能有多个控件对输入事件感兴趣。如果在某个阶段阻断了事件的传播,后续输入控件无法获得相应事件,因而无法对用户输入做出响应。

注意事件触发的顺序

在前面的文章中曾经提到过,键盘、input 和输入法事件的顺序不总是一定的。如果你的程序依赖这些事件的顺序,就要注意了。比如,在程序里假设 keydown 事件先触发(一般情况也是如此),对一些键(比如 Process Key)进行特殊处理,并停止传播。接下来是 composition 事件触发,处理一些事输入法相关的逻辑。然而在有些移动平台上,composition 总是先触发,那么 keydown 事件的特殊处理逻辑就漏掉了。


针对这种情况,我们在开发时可以多打一些 log,观察事件在运行时的实际顺序,便于发现问题。直接在浏览器的 DevTools 种调试可以,不过如果断点打在事件处理程序中,停留事件过长可能导致事件失效。另外,对一些移动端的浏览器,也没有 DevTools 可用。


断点失效


如上图,在同时在 composition 和 keydown 事件处理程序加断点,在 keydown 处停留后(16 行),后续的断点(7 行)没有进入。

移动端调试方法

其实针对移动端,还有其他调试的方法。如果移动设备浏览器无法查看 console 的 log,可以使用一些第三方的库来截获 log 的输出,并以浮动 UI 的方式显示在页面上,供开发者查看,如腾讯开源的 vConsole[3]。


我们也可以使用一些远程调试工具,将测试移动设备连接到 PC 上,开启设备的开发者选项,并启用 USB 调试功能,然后在 PC 的浏览器中通过 DevTools 调试页面。


  • 对于 Android 设备,以 Chrome 为例,可以参考官方文档[4]配置远程调试。注意,调试使用的 USB 线要具有传输功能,有的 Type-C 线只能给设备供电,却无法激活 USB 的调试功能。如果是三星的设备,可能还需要装驱动程序,可视具体情况查阅相关资料。Firefox 有类似的调试功能,这里不赘述。

  • 对于 iOS 设备,以 Safari 为例,可以参考这个文档[5]配置远程调试。推荐使用一台 Mac 机调试,注意如果 Safari 的菜单栏没有开发(Develop)选项,需要在设置中打开。如果机器上预装的 Safari 不好用,也可以尝试 Safari 的技术预览版[6],它提供了更强大的开发者选项。

掌握多语言的知识

最后一点实战技巧就是语言知识了。有时候自己写的代码总出 bug,主要是因为对相关语言的输入过程了解不够,因此忽略了很多边缘 case。当然,让每个工程师掌握多种语言知识是要求过高了,但针对键盘和输入法应用的开发者来说,有意识地积累这方面知识,对提供工作效率,写出高质量代码益处良多。


举个例子,汉字是由偏旁部首组成的,但如果我们用拼音输入,是整个字一起输进去的,而不是按偏旁部首的顺序逐个部分输入(像五笔输入法一样)。然而,韩文字符就不同,它需要通过一些类似偏旁的组件组合输入:字符“조”就是由“ㅈ”和“ㅗ”拼出的,在键盘上要依次输入 W 和 H 键。而且在删除时,也要先由“조”变为“ㅈ”,再完全删除,需要按两次退格键。


像这种情况如果开发者不清楚,那么在设计测试用例时,也无法保证好的覆盖了。

总结

这一讲我分享了一些开发中常见的、有点棘手的问题或者注意事项,希望对你有所帮助。从下一讲开始,我们通过一个在线输入法的小项目来实践一下。

参考阅读

[1] Event.preventDefault()

[2] Event.stopPropagation()

[3] Tencent vConsole

[4] Remote Debugging for Android Chrome

[5] Remote Debugging for iOS Safari

[6] Safari Technology Preview

系列导航

如果您对这个系列感兴趣,可以通过下面的导航找到对应文章👇🏻。

Web 键盘输入法应用开发指南(1)— 基本概念

Web 键盘输入法应用开发指南(2)— 键盘事件

Web 键盘输入法应用开发指南(3)— 输入法事件

Web 键盘输入法应用开发指南(4)— 组合键

Web 键盘输入法应用开发指南(5)— 实战技巧

发布于: 刚刚阅读数: 2
用户头像

天择

关注

还未添加个人签名 2020.09.07 加入

爱看点书的软件工程师 主页:zesi.tech 欢迎交流~

评论

发布
暂无评论
Web 键盘输入法应用开发指南 (5) —— 实战技巧_JavaScript_天择_InfoQ写作平台