如何为HTML输入框实现鼠标悬停自定义验证提示、禁用默认提示并避免无效框自动获焦
如何为HTML输入框实现鼠标悬停自定义验证提示、禁用默认提示并避免无效框自动获焦
刚好我之前也踩过类似的坑——想给表单输入框设置自定义的验证提示,结果浏览器默认的提示和我自己写的提示一起弹出来,而且鼠标悬停在无效字段上时还会自动获焦,体验特别差。折腾了一番终于搞定了,把完整的解决方案分享给你:
核心问题拆解与解决步骤
彻底禁用浏览器默认验证提示
首先要给<form>标签加上novalidate属性,这会告诉浏览器不要触发它自带的验证逻辑,完全交给我们的自定义代码处理。
另外还要修正验证函数里的判断条件:原来的if(element.validity !== ValidityState.valid)写法是错误的,因为element.validity是一个ValidityState对象,正确的判断元素是否无效的方式是检查!element.validity.valid这个布尔值。整合自定义验证逻辑(含字段对比校验)
我们要把两种验证场景整合到一起:- 单个字段未填写的情况,读取
data-error-message属性里的自定义提示 - 两个字段值重复的情况,弹出“必须输入不同的值”的提示
- 单个字段未填写的情况,读取
解决鼠标悬停自动获焦+提示自动消失
- 给输入框添加
mouseleave事件监听:当鼠标离开无效的输入框时,如果当前焦点正处于这个输入框上,就调用blur()让它失去焦点,避免自动获焦的问题 - 给验证提示添加定时器:提示弹出1秒后自动清除,提升用户体验
- 给输入框添加
完整可运行代码
<!DOCTYPE html> <html> <body> <form novalidate> <label for="field1">Field1:</label> <input id="field1" type="text" class="validate" data-error-message="You must fill in field1!" required /> <label for="field2">Field2:</label> <input id="field2" type="text" class="validate" data-error-message="You forgot to fill in field2!" required /> </form> <script> let validMsgTimeouts = {}; function validateInputElement(element) { let validationMessage = ""; // 检查单个字段是否无效,或两个字段值重复 if(!element.validity.valid || document.querySelector("input#field1")?.value?.trim() === document.querySelector("input#field2")?.value?.trim()) { // 优先处理字段重复的特殊提示 if(document.querySelector("input#field1")?.value?.trim() === document.querySelector("input#field2")?.value?.trim()) { validationMessage = "You must enter different values!"; } else { validationMessage = element.dataset["errorMessage"]; } } element.setCustomValidity(validationMessage); element.reportValidity(); // 设置提示自动消失定时器 if(validationMessage?.trim()?.length > 0) { validMsgTimeouts[element.id] = setTimeout(function() { element.setCustomValidity(" "); element.reportValidity(); clearTimeout(validMsgTimeouts[element.id]); }, 1000); } } // 给所有带validate类的输入框绑定事件 let nodeList = document.querySelectorAll("input.validate"); for(curElem of nodeList) { // 输入时清除提示 curElem.addEventListener("input", function(event) { event.target.setCustomValidity(""); event.target.reportValidity(); }); // 内容改变时触发验证 curElem.addEventListener("change", function(event) { validateInputElement(event.target); }); // 鼠标悬停时触发验证 curElem.addEventListener("mouseenter", function(event) { validateInputElement(event.target); }); // 鼠标离开时处理失焦,避免自动获焦 curElem.addEventListener("mouseleave", function(event) { let activeElement = document.activeElement; if(activeElement === event.target && activeElement.validationMessage?.trim()?.length > 0) { if(validMsgTimeouts[event.target.id]) { clearTimeout(validMsgTimeouts[event.target.id]); } activeElement.blur(); } }); } </script> </body> </html>
关键细节说明
novalidate属性是禁用默认提示的核心,没有它的话浏览器还是会偷偷弹出默认提示- 定时器
validMsgTimeouts用对象存储是为了给每个输入框单独管理定时器,避免多个输入框的定时器互相干扰 - 在
mouseleave事件里判断activeElement是为了确保只有当焦点确实在当前无效输入框上时才触发失焦,不会影响用户主动聚焦的情况
内容来源于stack exchange
相关产品推荐
相关产品推荐

