最近一直在学习.net core的用法。想法是通过写一个新闻系统来熟悉一下这个最新的技术。其实,我以前一直对.net技术都是浅尝辄止,最主要原因是没有动力。平时写企业站因为时间原因,不是使用php的框架就是用N年以前自己用asp写的系统直接上了。最近一直没什么活,决定试试。但在使用前端验证时有个问题一直很不喜欢。验证信息的显示方式太占用页面的空间。如果 显示在输入控件后面,就要为其留出足够的空间,这样看起来很不好看。如果显示在下面,会让界面一会儿高一会儿低的。就想解决一下。至于效果吗,有两种想法,一是泡泡提示效果,另一种是图标提示,两种都可以。于是去网上找各种资料,找到了几篇,大部分都是关于jquery-validation的,而且基本上都是修改原码来实现。这个不是我想要的。因为修改原码会很麻烦,一来,以后原码就无法升级了。二是如果想换一个效果就又要修改原代码。这个不符合切片精神。
于是想如果能象mvc中加过滤器一样,在错误信息显示过程中加入自定义的代码不就可以了吗?但查了很久资料,都没有找到这方面的内容。后来想,能不能来监听css的class的变动来实现呢。这个资料也没能找到中文的,后来在英文网站中找到一篇关于如何监听class改变的。http://forum.jquery.com/topic/firing-an-event-on-addclass,这里面提供了一思路,就是我们可以通过修改jquery的事件处理来实现监听任意事件。
这样,我们就可以不用修改原码而实现我们的想法。
先看一下运行结果:
验证错误信息不出现在页面上,而是当鼠标指上去时才会显示。当然,根据本文的方法,原则上可以实现任何显示效果。比如说气泡提示。
1、网页代码
网页是从mvc渲染后的页面中直接拷贝出来的。因为是实验性质的,所以css文件都没有带。有点难看。其中<img class='validImg' style="display:none;" src="images/validatebox_warning.png" title='' >是加在每一个需要前端验证的控件上,用来代替原来的那个<span>的。
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>JsDemo</title> <script type="text/javascript" src="jquery.js"></script> <script src="jquery.validate.js"></script> <script src="jquery.validate.unobtrusive.js"></script> <script src="my.js"></script> <style> .control-label{float:left;} </style> </head> <body> <form action="/Admin/Home/Login" onsubmit="return false;" method="post"> <div class="form-horizontal"> <div class="text-danger"></div> <div class="form-group"> <label class="col-md-2 control-label" for="LoginName">登录名称</label> <div class="col-md-10"> <input class="form-control" type="text" data-val="true" data-val-required="登录名称必输。" id="LoginName" name="LoginName" value="" /> <img class='validImg' style="display:none;" src="images/validatebox_warning.png" title='' > <span id="validSpanForLoginName" class="text-danger field-validation-valid" data-valmsg-for="LoginName" data-valmsg-replace="true"></span> </div> </div> <div class="form-group"> <label class="col-md-2 control-label" for="LoginPass">登录密码</label> <div class="cold-md-10"> <input class="form-control" type="password" data-val="true" data-val-length="登录密码长度必须小于50个字符。" data-val-length-max="50" data-val-required="登录密码必须输入。" id="LoginPass" name="LoginPass" /> <img class='validImg' style="display:none;" src="images/validatebox_warning.png" title='' > <span class="text-danger field-validation-valid" data-valmsg-for="LoginPass" data-valmsg-replace="true"></span> </div> </div> <div class="form-group"> <label class="col-md-2 control-label" for="CheckCode">验证码</label> <input class="form-control" type="text" data-val="true" data-val-required="验证码必须输入。" id="CheckCode" name="CheckCode" value="" /> <img class='validImg' style="display:none;" src="images/validatebox_warning.png" title='' > <span class="text-danger field-validation-valid" data-valmsg-for="CheckCode" data-valmsg-replace="true"></span> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10" style="padding-left:65px;"> <input type="submit" value="登录" class="btn btn-default" /> <!--<div class="poptip" > <span class="poptip-arrow poptip-arrow-bottom"> <em>◆</em> <i>◆</i> </span> 这是气泡提示,纯CSS[◆字符]写的哦 </div>--> </div> </div> </div> </form> </body> </html>
2、js代码
从上面提到的那篇 文章中我们知道,在jquery中可以通过将原方法进行替换的方法对一个方法进行添加功能,这很象mvc中的过滤器。其实真的很简单,就几行代码。
(function($){ $.each(["attr","css"],function(i,methodname){ var oldmethod = $.fn[methodname]; $.fn[methodname] = function(){ oldmethod.apply( this, arguments ); this.trigger(methodname+"change"); return this; } }); })(jQuery);
可能你会觉得$.each([], function(){});这个就是一个对数组进行遍历呀。为什么?
再往下看两行就明白了,就是使用$.fn['methodname']来取出要进行过滤的方法,然后对其进行添加代码处理,在这里只是简单地触发一个自定义事件,事件名称就是xxx+change。
这样,在页面中你只要去监听这个自定义事件就可以了。就象下面的代码一样,我只是简单地监听了所有前端验证显示控件对错误信息处理时要用到的两个事件(appendTo和removeData),因为不管如何处理,要想显示信息就要将内容加到页面上的控件中去,一定会使用appendTo或insert或insertBefore等方法来实现 。而当验证通过时也应该会使用相对应的方法将添加的信息去掉。当然,到底如何做,这个要看原码才行。
下面是jquery.validate.unobtrusive.js原码中关于如何显示验证错误信息的两部分原码:为什么是jquery.validate.unobtrusive.js?噢,忘了说,这是.net mvc,而不是直接使用jquery.validation.js,不过原理一样,如果你使用的是jquery.validation.js只要找到关键的显示错误信息的方法就行了。
有关错误信息显示的最重要的两个方法:
onError方法用来显示错误信息:
function onError(error, inputElement) { // 'this' is the form element var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"), replaceAttrValue = container.attr("data-valmsg-replace"), replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null; container.removeClass("field-validation-valid").addClass("field-validation-error"); error.data("unobtrusiveContainer", container); if (replace) { container.empty(); error.removeClass("input-validation-error").appendTo(container); } else { error.hide(); } }
onSuccess用来去掉错误信息,因为通过验证了。
function onSuccess(error) { // 'this' is the form element var container = error.data("unobtrusiveContainer"); if (container) { var replaceAttrValue = container.attr("data-valmsg-replace"), replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null; container.addClass("field-validation-valid").removeClass("field-validation-error"); error.removeData("unobtrusiveContainer"); if (replace) { container.empty(); } } }
从上面的两段代码我们可以看出,在显示错误信息时一定会调用appendTo方法,而通过验证时一定会调用removeData方法,所以在下面的代码中监听了这两个方法。
(function($){ $.each(["appendTo","removeData"],function(i,methodname){ var oldmethod = $.fn[methodname]; $.fn[methodname] = function(){ oldmethod.apply( this, arguments ); this.trigger(methodname+"change"); return this; } }); })(jQuery); $(document).ready(function(e){ //监听jquery中的appendTo事件而引发的自定义事件 $(".field-validation-valid").on('appendTochange', function(e){ var errText = $(this).children().eq(0).text(); if(errText.length>0) { $(this).parent().children('.validImg').attr('title', errText).show(); //将错误提示信息span隐藏起来 $(this).hide(); } //此时应该添加上去了一个子元素 }); // $(".field-validation-valid").on('removeDatachange', function(e){ //此时已经验证通过了 $(this).parent().children('.validImg').hide(); }); });