From fb771bc0136f2afca798b3b280168f3cbc3e31f5 Mon Sep 17 00:00:00 2001 From: subtrack Date: Mon, 19 Oct 2026 02:52:22 +0800 Subject: [PATCH] =?UTF-8?q?fix(v1.6.1):=20=E5=B0=8F=E9=94=AE=E7=9B=98?= =?UTF-8?q?=E7=82=B9=E5=87=BB=E4=B8=8D=E5=86=8D=E6=8A=A2=E8=B5=B0=E6=89=8B?= =?UTF-8?q?=E6=9C=BA=E5=B0=BE=E5=8F=B7=E8=BE=93=E5=85=A5=E6=A1=86=E7=84=A6?= =?UTF-8?q?=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 根因有两处: 1) 小键盘在 HTML 里是
的兄弟节点(不在表单内部),JS 用 pad.closest('form') 拿不到表单, 于是整个按键逻辑直接 return —— 按键既不写入输入框,也没有任何反馈; 2) 原生按钮在 mousedown 时会获得焦点,把输入框的焦点顶掉。 修复: - 改为先定位输入框,再用 input.form 反查表单,不再依赖 DOM 嵌套关系 - mousedown 阻止默认行为,按钮不再抢焦点;pointerdown / click 后统一把焦点与光标送回输入框末尾 - 未聚焦时点键盘会自动聚焦输入框;退格、确认逻辑不变 验证(真实 Chrome + CDP 真鼠标点击,不是单元模拟): - F-01/02 点 1 后焦点仍在、值为 1 - F-03/04 连点 1/2/3 得到 123,焦点保持 - F-05/06 退格得到 12,焦点保持 - F-07/08 输入框失焦后点键盘,自动聚焦并写入 - 截图 shots/v161-keypad-focus.png - 119 项验收回归全绿;版本号 1.6.1 --- internal/web/static/app.js | 38 ++++++++++++++++++++++++++++++-------- main.go | 2 +- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/internal/web/static/app.js b/internal/web/static/app.js index ac03c1d..27b31f8 100644 --- a/internal/web/static/app.js +++ b/internal/web/static/app.js @@ -145,12 +145,33 @@ } if (clocks.length) { tick(); setInterval(tick, 1000); } - /* 小键盘:输入手机尾号 */ + /* 小键盘:输入手机尾号 + 关键点:鼠标按下时阻止默认行为,否则按钮会先抢走输入框焦点; + 每次按键后再把焦点和光标送回输入框末尾。 */ Array.prototype.forEach.call(document.querySelectorAll('[data-keypad]'), function (pad) { - var form = pad.closest('form'); - if (!form) return; - var input = form.querySelector('input[name="tail"]'); - if (!input) return; + // 键盘是表单的兄弟节点(不在 内),所以先找输入框,再用 input.form 反查表单 + var scope = pad.closest('.drawer-block') || pad.parentElement || document; + var input = scope.querySelector('input[name="tail"]'); + if (!input) { return; } + var form = input.form; + if (!form) { return; } + + function keepFocus() { + try { input.focus({ preventScroll: true }); } catch (err) { input.focus(); } + var end = input.value.length; + try { input.setSelectionRange(end, end); } catch (err) { /* number 类型时忽略 */ } + } + + // mousedown 会触发“按钮获得焦点”,先拦下来;pointerdown 再兜底一次 + pad.addEventListener('mousedown', function (e) { + e.preventDefault(); + keepFocus(); + }); + pad.addEventListener('pointerdown', function () { + // 这里不能 preventDefault:会连带取消后面的 click 事件 + keepFocus(); + }); + pad.addEventListener('click', function (e) { var btn = e.target.closest('button[data-key]'); if (!btn) return; @@ -161,10 +182,11 @@ if (input.value) { if (form.requestSubmit) { form.requestSubmit(); } else { form.submit(); } } - } else { - if (input.value.length < 8) { input.value += key; } + return; + } else if (input.value.length < 8) { + input.value += key; } - input.focus(); + keepFocus(); }); }); diff --git a/main.go b/main.go index 1bf049e..8c78e7b 100644 --- a/main.go +++ b/main.go @@ -26,7 +26,7 @@ import ( "daili/internal/web" ) -const version = "1.6.0" +const version = "1.6.1" func main() { cfgFlag := flag.String("config", "", "配置文件路径(默认:exe 同级的 "+config.FileName+")")