实现HTML输入框Proper-Case时,如何识别自动补全按键事件?
补充CSS Text-Transform: Capitalize实现严格Proper Case输入
问题背景
要在HTML文本输入框强制实现Proper Case格式,CSS的text-transform: capitalize能实现大部分效果,但无法将连续大写字母转为小写,因此编写了对应的JavaScript代码。
测试中发现,用户选择自动补全选项时,触发的keyup和keydown事件不包含key属性。目前代码通过判断事件是否存在key属性识别自动补全,但有以下疑问:
- 是否有更规范、有文档支持的自动补全识别方法?
- 自动补全是否更应该归为
paste事件? - 有没有相关规范可以参考?
原实现代码
<!DOCTYPE html> <html> <head> <script type="application/javascript"> 'use strict'; document.addEventListener("DOMContentLoaded", isDOMIsGood); function isDOMIsGood() { // Handle autocomplete document.body.addEventListener('keyup', (e) => { if (e.target.tagName.toUpperCase() != "INPUT" || e.target.type.toUpperCase() != "TEXT" || getComputedStyle(e.target).textTransform.toUpperCase() != "CAPITALIZE" || ( "transform" in e.target.dataset && e.target.dataset.transform.toLowerCase() == "standard" )) return true; if ("key" in e) // not autocomplete return true; e.target.value = e.target.value.toLowerCase(); return true; } ); // Handle normal keyboard input document.body.addEventListener('keydown', (e) => { const WORD_DELIMS = ".,& -:"; // Needs work if (e.target.tagName.toUpperCase() != "INPUT" || e.target.type.toUpperCase() != "TEXT") return true; if (!("key" in e)) // autocomplete return true; if (e.key.length > 1 || e.altKey || e.ctrlKey || e.isComposing || e.metaKey || e.target.value.length == 0 || e.target.selectionStart == 0 || e.key > "Z" || e.key < "A" || ( "transform" in e.target.dataset && e.target.dataset.transform.toLowerCase() == "standard" ) || getComputedStyle(e.target).textTransform.toUpperCase() != "CAPITALIZE" || WORD_DELIMS.indexOf(e.target.value.substr(e.target.selectionStart - 1, 1)) != -1) return true; let cursorPos = e.target.selectionStart; e.target.value = e.target.value.substring(0, cursorPos) + String.fromCharCode(e.key.charCodeAt(0) + 32) + e.target.value.substring(cursorPos); e.target.selectionStart = ++cursorPos; e.target.selectionEnd = cursorPos; e.preventDefault(); e.stopPropagation(); return false; } ); // Handle paste document.body.addEventListener("paste", (e) => { const WORD_DELIMS = ".,& -:"; // Needs work if (e.target.tagName.toUpperCase() != "INPUT" || e.target.type.toUpperCase() != "TEXT" || getComputedStyle(e.target).textTransform.toUpperCase() != "CAPITALIZE" || ( "transform" in e.target.dataset && e.target.dataset.transform.toLowerCase() == "standard" )) return true; let paste = (e.clipboardData || window.clipboardData).getData('text'); if (paste.length == 0) return true; e.target.value = (e.target.value.substring(0, e.target.selectionStart) + paste + e.target.value.substring(e.target.selectionStart)).toLowerCase(); e.preventDefault(); e.stopPropagation(); return true; } ); // Allow the user, config file, etc set the enforcement level document.getElementById("properRules").addEventListener("click", (e) => { if (e.target.tagName.toLowerCase() == "input" && e.target.type.toLowerCase() == "radio" && e.target.name == "properCase") { var enhanced = document.getElementById("enhanced"); enhanced.dataset.transform = e.target.value; if (enhanced.dataset.transform == "none") enhanced.style.textTransform = "none"; else enhanced.style.textTransform = "capitalize"; } return true; } ); } </script> <style type="text/css"> input[type=radio]:checked { accent-color: lightblue;; } </style> </head> <body> <h1>Supplementing CSS Text-Transform: Capitalize</h1> <h2>How to enforce "Proper Case" on HTML input?</h2> <p>CSS Text-Transform will upcase each word if all lower case but not downcase multiple consecutive caps</p> <div id="outer"> <div> <label for="enhanced">Enhanced Capitalize:</label> <input id="enhanced" type="text" style="text-transform: capitalize; background-color: lightblue;" autocomplete="new-password" autofocus spellcheck="false" > <br><br> </div> <div id="properRules"> <p>"Proper Case" enforcement level:</p> <input type="radio" id="pc1" name="properCase" value="strict" checked=checked > <label for="pc1">Strict</label><br> <input type="radio" id="pc2" name="properCase" value="standard"> <label for="pc2">Relaxed</label><br> <input type="radio" id="pc3" name="properCase" value="none"> <label for="pc3">None</label><br> </div> </div> </body> </html>
解决方案与规范说明
1. 更可靠的自动补全识别方法
不要依赖key属性判断自动补全,这种方式属于浏览器行为的“副作用”,无规范保障。推荐使用**input事件**:
input事件会在输入框内容发生任何变化时触发,包括键盘输入、自动补全、粘贴、拖拽输入等所有场景,是DOM标准中专门用于监听元素值变化的事件。- 相比分散监听
keyup/keydown/paste,监听input事件可统一处理所有内容修改场景,代码更简洁,兼容性更好。
2. 自动补全不属于paste事件
自动补全和paste事件是完全不同的行为:
paste事件仅在用户通过剪贴板粘贴内容时触发,属于明确的剪贴板操作。- 自动补全是浏览器或第三方插件基于预设数据填充内容的行为,属于用户输入的一种变体,应归为
input事件的处理范畴。
3. 相关规范参考
- DOM Level 3 Events规范:明确定义
input事件用于表示元素值的修改,涵盖所有用户或程序导致的内容变化场景。 - HTML标准:对
autocomplete属性的行为有明确说明,但事件处理仍遵循DOM Events规范,所有输入类操作的统一入口是input事件。
优化后的代码思路
将原有的keyup/keydown/paste事件监听替换为input事件,在事件回调中统一处理内容的Proper Case转换,同时保留原有的规则判断(如text-transform属性、data-transform配置等),可覆盖所有输入场景,包括自动补全。
内容的提问来源于stack exchange,提问作者McMurphy
相关产品推荐
相关产品推荐

