拓冰建站拓冰建站
首页 / 资讯中心 / 正文

面向PC端与自助终端的jQueryUI虚拟键盘方案:布局配置、安全输入与工程实践

简介这是一款基于 jQuery UI 的虚拟键盘插件 VirtualKeyboard面向需要提升网页表单输入体验的前端开发者尤其适合触摸屏设备、密码输入及对安全有要求的场景。它模拟真实键盘提供字母、数字和符号布局并支持 jQuery UI 多主题、自定义按键顺序和特殊字符开发者可通过 JSON 布局或初始化参数灵活控制键盘行为。资源包以 zip 形式提供大小约 1.27MB文件总数显示为 0具体文件类型明细未列出实际内容应包含插件运行所需的 CSS、JS 及演示样例解压后可直接引入项目试用。该插件现已适配 Chrome、Firefox、Safari、Edge 和 IE9并兼容 jQuery Mobile可在手机和平板上流畅使用。已有 295 人浏览学习。通过阅读配套代码和说明读者能快速掌握其初始化方法、事件监听、开合控制与动态配置方式从而减少重复开发为表单输入模块加入更安全、更友好的交互体验。1. 这个项目解决的痛点为什么PC端也需要虚拟键盘很多人一看到虚拟键盘四个字下意识觉得这是移动端的东西手机平板上弹出个键盘点一点完事。但真实项目的需求往往比这复杂得多。我做过的几个实际场景里虚拟键盘的需求全都来自桌面端和嵌入式终端没有一个是手机页面。先举几个典型的例子医院的自助挂号机、商场的互动查询屏、银行网点的业务终端、工厂产线上的信息录入设备。这些设备的共同点是——根本没有物理键盘或者物理键盘被物理屏蔽了。屏幕是触控的系统跑的是Windows或Linux加浏览器这时候你总不能让用户去外接一个键盘来输入姓名和手机号吧。另一个相反的场景也很有意思某些安全等级比较高的系统比如网银登录、后台管理密码输入明明有物理键盘但故意要用鼠标点虚拟键盘。目的很直白就是为了防本地的键盘记录器。这种需求在金融、政务类项目中特别常见。所以VirtualKeyboard这类插件的定位非常清晰给浏览器里的页面提供一套完整的、可配置的鼠标点击/触摸点击输入方案不依赖物理键盘。它能输出普通字符、数字、功能键也可以扩展成身份证号键盘、车牌号键盘这种专用布局。适合的目标读者包括做自助终端项目的前端工程师、做后台管理系统需要强化登录安全度的团队、以及做电子教室或演示系统的开发者。如果你只是做个普通的表单页面物理键盘够用那确实不需要它但只要你碰到上述任意一种场景手写一套虚拟键盘的成本会迅速超过你的预期。2. 为什么选择基于jQueryUI实现主题联动是最大红利选定技术方案之前我也纠结过是纯手写还是找一个现成插件。纯手写的思路就是生成一堆button元素绑定click事件往目标input里塞字符。这个方案一听就很简单但是真的落地到项目里问题立刻冒出来按键布局怎么配Shift切换逻辑怎么写按下和抬起的状态样式怎么处理键盘怎么跟随输入框位移输入框禁用时键盘要不要变灰一连串问题做完你会发现写一个能用的虚拟键盘只要两个小时写一个真正像样的虚拟键盘要两个星期。选择基于jQueryUI最核心的一个原因是主题系统。jQueryUI自带了一套非常成熟的ThemeRoller主题机制从jQueryUI 1.8到1.12所有的组件——按钮、对话框、进度条、日期选择器——都共享同一套CSS变量。这意味着如果你把VirtualKeyboard做成jQueryUI组件那么你的键盘按钮可以天然复用jQueryUI的按钮样式你的键盘面板可以复用dialog的边框和阴影定义。项目里如果已经用了jQueryUI的其他组件新加一个键盘功能视觉上不需要额外写一堆CSS换肤的时候也只需要换一个主题文件键盘自动跟着变。这种联动效果是纯手写方案完全做不到的。另一个红利来自jQueryUI的**组件工厂Widget Factory**机制。你在浏览器控制台里能直接看到$(selector).keyboard()这样的调用方式这个模式让组件的初始化、销毁、参数覆盖、事件回调都有一套标准语法。团队协作时新成员只要用过jQueryUI任意一个组件就能很快上手VirtualKeyboard。我见过有些开发者会用纯JavaScript写插件然后对外暴露一堆全局函数调用方式非常随意项目维护到后期根本不知道谁调了谁。用jQueryUI的widget机制所有状态管理都在实例内部通过option方法统一读写代码组织清晰得多。不过我要提醒一句jQueryUI现在官方已经不再积极更新了这个项目如果用得上通常是在维护存量系统。如果你是从零开始的新项目且没有历史包袱我后面会讲到Vue或React版本的替代方案。但如果你是做传统多页应用、服务端渲染页面或者老系统功能增强jQueryUI依然是十分顺手的选择——毕竟你大概率不会因为一个键盘去把整个系统的jQuery版本都升级掉。3. VirtualKeyboard核心功能拆解布局配置、按键映射、输入输出与状态管理3.1 按键布局用JSON描述整个键盘VirtualKeyboard把键盘布局做成了纯数据驱动。你不需要改HTML也不需要render一堆代码来画键盘只需要给插件传一个布局对象。一个最基本的全键盘布局长这样var layout { default: [ 1 2 3 4 5 6 7 8 9 0 - {bksp}, {tab} q w e r t y u i o p [ ] \\, {lock} a s d f g h j k l ; \ {enter}, {shift} z x c v b n m , . / {shift}, {space} ], shift: [ ~ ! # $ % ^ * ( ) _ {bksp}, {tab} Q W E R T Y U I O P { } |, {lock} A S D F G H J K L : {enter}, {shift} Z X C V B N M ? {shift}, {space} ] };这个结构其实非常直观每行是一个字符串数组空格分隔每个按键。{bksp}这类带花括号的标记是功能键插件会特殊处理。layout对象里可以同时定义多套布局default是默认显示shift是按住Shift后切换的样子也可以扩展成caps或数字专用布局。自定义按键时每个按键可以是一个纯字符串也可以是一个对象用来支持更细的配置var layoutWithConfig { default: [ [ { value: 1, label: 一, css: key-num }, { value: abc, label: ABC, action: toggleCase }, 3 ] ] };这里的value是最终输出到输入框的内容label是按键上显示的文字css可以给单独的键加样式类action可以绑定内置动作。这个设计让我在项目里省了很多事——自定义一个车牌号键盘的时候只要调整layout把汉字和字母按规则排列好就行插件的渲染逻辑完全不用动。3.2 输入输出与控制流程键盘的输入流程比很多人想象的要复杂一点。它不是一个简单的click往里塞字符而是模拟了物理键盘的完整生命周期。我在使用过程中整理了它的内部处理顺序触发显示用户点击输入框插件根据配置决定是否自动弹出键盘面板击键阶段鼠标按下mousedown时按键进入高亮状态并播放按下样式此时字符预写入缓冲区鼠标抬起后样式恢复。这里用mousedown而不是click是为了让用户体验更接近物理键盘——按下那一刻就有反馈而不是等松开才反应输出目标判定插件根据配置的target属性找到目标输入框把当前按下的值插入光标所在位置。这里有个细节它处理了textarea和input的selectionStart/selectionEnd所以支持在文字中间插入而不是永远追加到末尾Shift状态切换按一下Shift键盘布局从default切换为shift集合再按一下切回来。CapsLock是独立的状态切换后只影响字母大小写不影响数字符号层后续动作按下Enter键时根据enterAction配置决定是提交表单、换行还是只触发回调按下Tab键可以在表单字段间跳转。插件对外暴露的事件回调覆盖了整个过程最常用的两个是beforeChange和afterChange。前者可以在字符进入输入框之前拦截修改比如某些场景下要过滤特殊字符、限制输入长度后者可以用于联动其他业务逻辑比如输入完毕后自动搜索。$(#input-demo).virtualKeyboard({ layout: layout, target: #input-demo, beforeChange: function(e, key, value) { // 返回false则取消本次输入 if (value x) return false; }, afterChange: function(e, key, value) { console.log(当前输入框内容:, value); } });3.3 焦点管理容易被忽略却决定体验的部分虚拟键盘最容易被忽略的坑就是焦点管理。你想想看用户用鼠标点虚拟键盘上的按钮时焦点会从输入框转移到按钮上。如果监听的是click事件第一次点击后再点虚拟键盘的按钮输入框已经失去焦点了后面的输入就可能失效。这个问题在很多简易键盘里反复出现。VirtualKeyboard的解决方式是在内部维护一个逻辑焦点初始化时记录目标输入框元素按键期间始终把焦点保持在该输入框上按钮元素的mousedown事件使用preventDefault()阻止默认的焦点转移行为。这招相当实用我在排查别的键盘插件时发现很多插件恰恰是栽在这一步上。另外它还统筹了键盘面板的定位与显示默认收到焦点后键盘出现在输入框下方当空间不够时会自动调整到上方。这个定位逻辑用的是jQuery UI的position工具函数和对话框、提示条的定位机制是同源的所以行为很稳定。4. 从引入到上线完整接入步骤与常用配置项4.1 三步完成基本接入在页面里集成VirtualKeyboard一共就三步引入资源文件、写一个输入框、调用插件初始化。第一步引入依赖文件。因为是基于jQueryUI的所以jQuery、jQueryUI的核心样式、jQueryUI核心脚本、插件自身的脚本和样式一个都不能少。顺序不能乱jQuery的引入必须排在jQueryUI之前link relstylesheet hrefjquery-ui.min.css link relstylesheet hrefvirtual-keyboard.min.css script srcjquery.min.js/script script srcjquery-ui.min.js/script script srcvirtual-keyboard.min.js/script第二步准备一个输入框。可以是input也可以是textarea插件会自动识别元素类型调整行为input typetext idusername placeholder点击弹出键盘 autocompleteoff第三步初始化插件$(#username).virtualKeyboard({ layout: qwerty, tab: enable, enterAction: blur, alwaysOpen: false, autoAccept: true });layout: qwerty是内置的QWERTY布局如果你有特殊布局需求可以传自定义layout对象。autoAccept: true表示点击键盘外部时自动关闭键盘并保留输入内容省去了单独做确认按钮的操作这个配置在自助终端上特别好用。4.2 常用配置项速查下面是我在多个项目中用过的、比较常用的配置项整理成表格方便对照配置项可选值默认值作用说明layoutqwerty / numeric / 自定义对象qwerty键盘布局target字符串选择器 / jQuery对象当前输入框输出的目标元素alwaysOpentrue / falsefalse键盘是否常驻显示false时点击输入框才弹出autoAccepttrue / falsetrue点击外部时是否直接接受当前输入内容enterActionblur / submit / nothingblurEnter键行为关闭键盘、提交表单或无动作shiftKeyActivetrue / falsetrue是否启用Shift切换大写/符号布局lockInputtrue / falsefalse锁定输入方式为仅点击禁止物理键盘输入stickyShifttrue / falsetrueShift按下一次后是否保持到下一次按键再取消appendLocallytrue / falsefalse选择器结果是否限定在组件的父级容器内查找usePreviewtrue / falsefalse是否在键盘顶部显示一个输入预览条lockInput这个配置值得多说两句。在自助查询机上如果屏幕本身没有物理键盘但系统还连着USB键盘口用户可能误触物理键盘输入进来导致数据异常。设置lockInput: true后插件会拦截目标输入框的物理键盘输入只能通过虚拟键盘点击输入从源头隔绝了错误输入。在金融项目里这个配置配合防截屏策略基本就是标准姿势了。4.3 接口调用与事件绑定jQueryUI组件的特点之一就是所有交互都通过标准方法暴露。VirtualKeyboard常用的方法有// 打开键盘 $(#username).virtualKeyboard(show); // 隐藏键盘不改变当前已输入内容 $(#username).virtualKeyboard(hide); // 销毁键盘实例还原为普通输入框 $(#username).virtualKeyboard(destroy); // 动态修改配置 $(#username).virtualKeyboard(option, autoAccept, false); // 获取当前键盘状态 var isOpen $(#username).virtualKeyboard(isOpen);事件绑定则统一遵循jQueryUI的on(事件名, handler)格式我在实际项目里最常用的是这几个$(#username).on(keyboardChange.virtualKeyboard, function(e, value) { // 每次输入内容变更时触发 doSearch(value); }); $(#username).on(keyboardOpen.virtualKeyboard, function() { // 键盘打开时可以在这里重置某些业务状态 }); $(#username).on(keyboardClose.virtualKeyboard, function(e, value) { // 键盘关闭时把当前值提交到后端做校验 });事件后缀.virtualKeyboard是一个命名空间它不影响我们可能绑定的其他jQuery事件两个事件体系是隔离的。这个设计在大型项目里非常实用不用担心和业务代码冲突。5. 往真实业务场景落地时的几个关键考量5.1 自助终端场景触摸事件的兼容处理做自助终端项目和做普通Web项目最大的不同是触控环境下的点击事件会有300毫秒左右的延迟。这个延迟在物理键盘输入时察觉不到但用触摸屏点虚拟键盘时非常明显连续输入时感觉像年纪大了反应慢半拍。解决思路是在插件初始化后把mousedown事件映射到touchstart。具体实现不复杂$(document).on(touchstart, .vk-btn, function(e) { e.preventDefault(); $(this).trigger(mousedown); });但需要注意一个细节touchstart触发后浏览器随后还是会派发模拟的mouse事件。如果不做处理一个按键会触发两次输入。所以在这个映射逻辑里要加上一个标记在touch环境下一个按键周期内只响应一次。这个坑我在第一版方案里踩过后来直接在测试机上验证了一下修复方式是监听一次touchstart后立即移除mousedown的监听等下一次mousedown发生再重新绑定。5.2 安全输入场景组合前端策略并用如果虚拟键盘用于密码输入前端只需要做到这个程度输入框不用原生input而是用模拟的展示层把真实密码只保留在JS变量里键盘按键不产生落到DOM上的明文输入痕迹。同时清空浏览器的自动填充记录、禁止右键粘贴、禁止物理键盘输入。这些VirtualKeyboard通过配置项都能实现但我要提醒你前端虚拟键盘能防住的是本地的键盘记录器对网络抓包和恶意浏览器插件是无效的。真正的安全密码输入必须配合HTTPS传输、服务端加密、必要时用控件级安全输入组件。所以正确的心态是虚拟键盘在安全体系里起到的是提高攻击成本的辅助作用不是银弹。以下这个组合是金融项目比较标准的做法防护层手段负责方输入层虚拟键盘、禁用自动填充、禁用粘贴前端插件传输层HTTPS 敏感字段加密网关/后端存储层哈希加盐、硬件加密模块服务端5.3 性能和资源占用老设备的生死线自助终端设备的性能差异巨大有的机器甚至是十年以上的工控机内存只有2GB跑个Chrome都费劲。这种环境下虚拟键盘的性能问题就暴露出来了。我做过一次性能测试在低端商显平板上初始化VirtualKeyboard整对象包含约45个按键每个按键都是一个带jQueryUI样式类的span元素。首次弹出耗时大概80毫秒这个数字在可接受范围内。但如果页面里同时有多个输入框每个输入框都初始化了一个键盘实例内存占用会线性上升。所以要注意一个细节尽可能复用实例而不是为每个输入框重复创建。VirtualKeyboard支持多个输入框共享同一个键盘实例通过target配置在切换输入框时动态改变输出目标。实际操作时可以监听所有输入框的focus事件统一指向同一个键盘实例。我录制过一组对比数据供参考单实例单输入框首次弹出约80ms键盘面板常驻后无额外内存增长单实例多输入框动态切换target首次弹出约80ms切换目标无额外开销每输入框独立实例5个输入框首次弹出约80ms但内存占用增长约4倍切换输入框时会看到轻微卡顿。所以如果页面上有多个输入点极其推荐用共享实例的方式。6. 常见问题排查与优化经验6.1 键盘不跟随输入框怎么办一个高频问题是页面滚动或窗口大小变化后键盘面板还停在原地和输入框对不上了。这个问题的根源在于键盘面板的定位是相对于视口的输入框移动后没有重新计算位置。解决办法是在页面滚动和resize事件里重新调用一次定位函数。代码大致长这样$(window).on(scroll resize, function() { if ($(#username).virtualKeyboard(isOpen)) { $(#username).virtualKeyboard(refresh); } });Vue或React的单页应用尤其要注意这个坑。框架路由切换后旧页面的滚动事件可能还绑定着容易泄露内存。建议在组件销毁时同时调用destroy方法把实例清理干净。6.2 中文输入法状态下的字符冲突如果目标输入框仍然允许物理键盘输入用户输入中文时用虚拟键盘想补一个字母拼音输入法是开启状态点击虚拟键盘的字母键可能直接进了输入法的候选区而不是进输入框。这个问题在安全键盘场景下基本不会出现因为lockInput: true会强制禁掉物理键盘输入。但在混合输入场景里确实会遇到。我的建议是按业务需求二选一一是干脆锁定物理输入只允许点击输入二是当虚拟键盘弹出时先用程序暂时禁用输入法$(#username).on(keyboardOpen.virtualKeyboard, function() { this.style.imeMode disabled; });imeMode这个属性Chrome和Edge都支持能让输入法在这个输入框上不激活。实测下来能解决绝大多数输入法冲突问题。6.3 自定义皮肤的正确姿势jQueryUI的ThemeRoller是换肤的标准路径正常使用主题文件即可。但如果你只想微调键盘的配色又不想覆盖整个jQueryUI主题VirtualKeyboard预留的CSS变量和类名前缀就派上用场了。它所有的元素都有统一的命名空间类比如按键是.vk-btn面板是.vk-container功能键额外有.vk-bksp、.vk-enter这类标识。你不需要修改插件源码直接在项目里覆盖这些类的样式即可.vk-container { border-radius: 8px; box-shadow: 0 4px 12px rgba(0,0,0,0.2); } .vk-btn { min-width: 44px; height: 44px; border-radius: 4px; font-size: 16px; } .vk-btn.vk-bksp { background: #f0f0f0; }需要注意覆盖顺序项目自定义样式一定要排在插件CSS之后引用否则会被插件的样式优先规则覆盖掉。我自己习惯的做法是把插件样式单独打包成一个文件然后在后面追加一个keyboard-overrides.css。这样升级插件版本的时候不会牵连到自定义样式。6.4 按需加载与体积优化VirtualKeyboard压缩后的JS文件大约30KB左右这个体积对于传统多页应用来说完全不是问题。但如果你的项目本身已经在为首屏体积发愁可以考虑按需加载只在用户聚焦到需要虚拟键盘的输入框时动态加载插件脚本。webpack的动态import语法就可以实现function initVirtualKey() { return import(/* webpackChunkName: virtual-keyboard */ ./virtual-keyboard).then(function(module) { $(#username).virtualKeyboard(module.default); }); } $(#username).on(focus, function() { initVirtualKey(); });这个方式实测能把首屏JS体积减少约35KB对性能要求严格的项目有帮助。不过要注意动态加载期间用户可能已经点了输入框所以最好提前加载——在页面ready后、用户点击之前就预加载好或者做个节流逻辑。7. 更新迭代视角老插件如何续命虽然这款插件基于jQueryUI按前端框架的更替速度看已经算老古董了但它的思路和API设计依然有可取之处。如果你的项目正好要用它几个建议供参考。第一给插件写一层薄封装。无论是用在jQuery项目还是哪个框架项目里业务代码都尽量不要直接散落地调用插件方法而是封装成一个独立的工具模块。例如做一个SafeKeyboard类内部统一管理VirtualKeyboard的初始化、销毁、动态切换目标对外只暴露open、close、getValue三个方法。以后就算要换掉底层实现业务代码一行都不用改。第二明确维护边界。因为插件依赖的jQueryUI本身处于维护冻结状态别指望出现安全更新或新特性。我的做法是在项目文档里固定住jQuery、jQueryUI、VirtualKeyboard三个依赖的版本号禁止随意升级。线上出问题优先排查业务代码而不是升级依赖。第三如果是从零开始的新项目又非要键盘功能现在的主流通路是找Vue/React的键盘组件或者用Canvas自绘一套。基于jQueryUI的VirtualKeyboard更适合存量系统的功能增强。我的一个老项目里整个后台还在用jQueryUI的日期选择器和对话框加入这个虚拟键盘之后界面风格浑然一体毫无违和感——这种融入感是新框架组件很难替代的。说到底技术选型没有绝对的新旧对错核心是匹配你当前项目的技术栈和维护成本。VirtualKeyboard这套基于jQueryUI的实现方式在特定场景下依然是快速落地虚拟键盘需求的最短路径。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门