【翻译】创建 HTML5 表单验证气泡的替代方案
作者:佚名 来源:小影志 时间:2014-10-13
在过去几年里,我发表了关于 HTML5 表单验证的文章和演讲,其中最常见的问题就是关于气泡。这里的气泡是指浏览器显示验证错误信息的 UI 空间。下面分别是 Chrome、Firefox 和 IE 的实现:
无论什么原因,我们开发者(或更可能是设计师同学)都有很强的欲望想样式化这些东西。但不幸的是我们不做不到,因为没有一款浏览器提供指向这些气泡的样式。Chrome 曾经提供了一系列带供应商前缀的伪元素(::-webkit-validation-bubble-*
),但是它们在 Chrome 28 中被移除了。
那么开发者可以做什么呢?虽然浏览器不允许你自定义他们的气泡,但 constraint validation spec 可以允许你阻止浏览器的气泡 UI 并让你自己创建。文章的余下部分将向你如何做到这一点。
警告:不要轻易的创建气泡替代方案。使用默认的气泡,可以免费获得一些非常复杂的功能,比如定位和可达性。使用自定义气泡你需要自己解决这些问题(或使用库替代)。
阻止默认气泡
创建自定义 UI 的第一步是阻止原生气泡。你可以通过监听表单控件的 invaild
事件并阻止其默认行为。举例来说,下面的表单没有验证气泡,因为在 invalid
事件处理函数中调用了 event.preventDefault()
。
<script>
document.querySelector( "input" ).addEventListener( "invalid",
function( event ) {
event.preventDefault();
});
</script>
invaild
事件并没有冒泡,所以如果你想阻止在多个元素上的验证气泡,你必须注册一个捕获阶段的事件监听。
如果你不了解 DOM 事件中冒泡和捕获阶段的区别,这篇 MDN 文章给出了不错的解释。
下面的代码通过在父元素
你可以通过这个方法移除浏览器的表单验证 UI,但是你一旦这样做,你必须建立一些自定义的来替代它。
建立替代 UI
显示表单验证错误的方法不计其数。没有一种是绝对的正确或者错误(好吧,有些错误的实现方法)。让我们来看看这几种你可能会采用的常见方法。对每一个,我们都会使用如下非常简单的名称和邮箱地址表单。我们还将使用一些简单的 CSS 让这份表单看起来还不错。
在开始之前有一个重要的点需要说明:所有这些 UI 只在 Internet Explorer 10 及以上版本可用,constraint validation API 在旧版中不存在。如果你需要支持旧版 IE 并且仍然希望使用 HTML5 表单验证,在这个幻灯片中我概括了一些可选方案。
替代 UI #1: 消息列表
一种显示验证错误消息的常见方式就是显示在屏幕顶部的一个框中,并且这种行为比较容易和 HTML5 表单验证 API 建立结合。在进入到代码部分之前,这是实际应用中的样子:
下面是你建立这个 UI 所需的代码:
function replaceValidationUI( form ) {
// Suppress the default bubbles
form.addEventListener( "invalid", function( event ) {
event.preventDefault();
}, true );
// Support Safari, iOS Safari, and the Android browser—each of which do not prevent
// form submissions by default
form.addEventListener( "submit", function( event ) {
if ( !this.checkValidity() ) {
event.preventDefault();
}
});
// Add a container to hold error messages
form.insertAdjacentHTML( "afterbegin", "
" ); var submitButton = form.querySelector( "button:not([type=button]), input[type=submit]" ); submitButton.addEventListener( "click", function( event ) { var invalidFields = form.querySelectorAll( ":invalid" ), listHtml = "", errorMessages = form.querySelector( ".error-messages" ), label; for ( var i = 0; i < invalidFields.length; i++ ) { label = form.querySelector( "label[for=" + invalidFields[ i ].id + "]" ); listHtml += "
" + label.innerHTML + " " + invalidFields[ i ].validationMessage + "
"; } // Update the list with the new error messages errorMessages.innerHTML = listHtml; // If there are errors, give focus to the first invalid field and show // the error messages container if ( invalidFields.length > 0 ) { invalidFields[ 0 ].focus(); errorMessages.style.display = "block"; } }); } // Replace the validation UI for all forms var forms = document.querySelectorAll( "form" ); for ( var i = 0; i < forms.length; i++ ) { replaceValidationUI( forms[ i ] ); }
这个示例为每个表单字段设定了一个对应的 ,并且 的
for
属性设置成和表单字段的id
属性一样。你也许想调整代码,建立消息以适配你自己的应用,但是其他的方法也许更容易达到目的。替代 UI #2: 字段下面的消息
有时候,和在屏幕顶部显示消息列表相比,你更想把消息和他的对应字段管理起来。下面的 UI 实现了这点:
要建立这个 UI,大部分代码和第一种方法相同,只是在提交按钮的
click
事件处理函数上有些细小区别。function replaceValidationUI( form ) { // Suppress the default bubbles form.addEventListener( "invalid", function( event ) { event.preventDefault(); }, true ); // Support Safari, iOS Safari, and the Android browser—each of which do not prevent // form submissions by default form.addEventListener( "submit", function( event ) { if ( !this.checkValidity() ) { event.preventDefault(); } }); var submitButton = form.querySelector( "button:not([type=button]), input[type=submit]" ); submitButton.addEventListener( "click", function( event ) { var invalidFields = form.querySelectorAll( ":invalid" ), errorMessages = form.querySelectorAll( ".error-message" ), parent; // Remove any existing messages for ( var i = 0; i < errorMessages.length; i++ ) { errorMessages[ i ].parentNode.removeChild( errorMessages[ i ] ); } for ( var i = 0; i < invalidFields.length; i++ ) { parent = invalidFields[ i ].parentNode; parent.insertAdjacentHTML( "beforeend", "
" ); } // If there are errors, give focus to the first invalid field if ( invalidFields.length > 0 ) { invalidFields[ 0 ].focus(); } }); } // Replace the validation UI for all forms var forms = document.querySelectorAll( "form" ); for ( var i = 0; i < forms.length; i++ ) { replaceValidationUI( forms[ i ] ); }
替代 UI #3: 替代气泡
最后一个 UI 介绍了一种通过 JavaScript 模仿浏览器验证气泡的方式,一种完全自定义(和可样式化)的气泡。以下是实际应用:
在这个示例中我使用了 Kendo UI tooltip,因为我不想考虑该如何处理气泡的定位逻辑。下面是我建立这个 UI 的代码。在这个实现中我选择了使用 jQuery 来清理 DOM 代码(Kendo UI 依赖于 jQuery)。
$( "form" ).each(function() { var form = this; // Suppress the default bubbles form.addEventListener( "invalid", function( event ) { event.preventDefault(); }, true ); // Support Safari, iOS Safari, and the Android browser—each of which do not prevent // form submissions by default $( form ).on( "submit", function( event ) { if ( !this.checkValidity() ) { event.preventDefault(); } }); $( "input, select, textarea", form ) // Destroy the tooltip on blur if the field contains valid data .on( "blur", function() { var field = $( this ); if ( field.data( "kendoTooltip" ) ) { if ( this.validity.valid ) { field.kendoTooltip( "destroy" ); } else { field.kendoTooltip( "hide" ); } } }) // Show the tooltip on focus .on( "focus", function() { var field = $( this ); if ( field.data( "kendoTooltip" ) ) { field.kendoTooltip( "show" ); } }); $( "button:not([type=button]), input[type=submit]", form ).on( "click", function( event ) { // Destroy any tooltips from previous runs $( "input, select, textarea", form ).each( function() { var field = $( this ); if ( field.data( "kendoTooltip" ) ) { field.kendoTooltip( "destroy" ); } }); // Add a tooltip to each invalid field var invalidFields = $( ":invalid", form ).each(function() { var field = $( this ).kendoTooltip({ content: function() { return field[ 0 ].validationMessage; } }); }); // If there are errors, give focus to the first invalid field invalidFields.first().trigger( "focus" ).eq( 0 ).focus(); }); });
虽然替换验证气泡需要的代码量不少,但是这带来了相当于浏览器实现的复刻版。不同之处在于 JavaScript 的实现有着更多的可定制性,实现你的心中所想。举例来说,如果你想添加一些粉色、绿色和 Comic Sans 到你的气泡中,你现在完全可以做到:
Kendo UI tooltip 小工具是 Kendo UI Core 中25+个小工具之一,来自 Kendo UI 免费和开源分发。
所以你可以在当下使用这份代码而无须担心授权限制 — 或付费。你可以直接下载 Kendo UI core 源码,或使用我们的 CDN,或者从 Bower 抓取库(bower install kendo-ui-core)
结束语
虽然你不能样式化浏览器的验证气泡,但你可以阻止他们并建立你自己的 UI。你可以随意尝试更改文章中的实现方式来迎合你自己的需求。如果你曾经使用过其他方式也欢迎留言分享。
原文:Building HTML5 Form Validation Bubble Replacements
翻译:小影
相关阅读
更多资讯
-
Whats the Closest Google Font? 找到最好的 Google Web 字体
-
完美防止垃圾邮件的6种方式 - 让Spam爬虫空手而归
-
常用 JavaScript 库 CDN 加速服务
-
JavaScript and CSS Code Beautifier - 代码格式化高亮扩展
-
【译】使用 Intersection Observer 实现图片延迟加载
-
使用 Web Audio API 播放摩斯密码
-
【译】如何创造带方向感应的纯 CSS 悬停效果
-
Kraken.io - 最好用的在线图片压缩工具
-
Polyfill.io - 自动化的 JavaScript Polyfill 服务
-
CSS3介绍
-
使用 SVG 实现手写签名动画效果
-
Fontmin - 中文 WebFont 子集化生成工具