如何在.Net Core MVC中为动态表单开启客户端验证
- GitHub:https://github.com/aspnet/jquery-ajax-unobtrusive
-
jquery.unobtrusive-ajax的一些文章
jquery.unobtrusive-ajax.js源码阅读
/*! ** Unobtrusive Ajax support library for jQuery ** Copyright (C) Microsoft Corporation. All rights reserved. */ /*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */ /*global window: false, jQuery: false */ /* data-ajax=true //开启绑定 data-ajax-mode//更新的形式 BEFORE插入到对象之前 AFTER插入到对象之后 为空就是覆盖 data-ajax-update//更新的对象 data-ajax-confirm//设置一个确定取消弹出框的文字,没有则不设置 data-ajax-loading//显示loading的对象 data-ajax-loading-duration//持续时间 默认是0 data-ajax-method//提交方式 data-ajax-url//提交url data-ajax-begin//ajax前触发的函数或者一段程序 data-ajax-complete//完成后,此时还没有加载返回的数据,请求成功或失败时均调用 data-ajax-success//成功,加载完成的数据 data-ajax-failure//失败 */ (function ($) { var data_click = "unobtrusiveAjaxClick", data_validation = "unobtrusiveValidation"; //第二核心,判断是否函数,不是则构造一个匿名函数 function getFunction(code, argNames) { var fn = window, parts = (code || "").split("."); while (fn && parts.length) { fn = fn[parts.shift()]; }//查找函数名有时候是命名空间比如xxx.xxx if (typeof (fn) === "function") { return fn; } argNames.push(code); //如果不是函数对象则自己构造一个并返回,吊! return Function.constructor.apply(null, argNames); } function isMethodProxySafe(method) { return method === "GET" || method === "POST"; } //可以添加各种提交方式,应该是为Web Api做的补充 function asyncOnBeforeSend(xhr, method) { if (!isMethodProxySafe(method)) { xhr.setRequestHeader("X-HTTP-Method-Override", method); } //注:X-HTTP-Method-Override是一个非标准的HTTP报头。 //这是为不能发送某些HTTP请求类型(如PUT或DELETE)的客户端而设计的 } //完成后的 function asyncOnSuccess(element, data, contentType) { var mode; if (contentType.indexOf("application/x-javascript") !== -1) { // jQuery already executes JavaScript for us return; } mode = (element.getAttribute("data-ajax-mode") || "").toUpperCase(); $(element.getAttribute("data-ajax-update")).each(function (i, update) { var top; switch (mode) { case "BEFORE": top = update.firstChild; $("<div />").html(data).contents().each(function () { update.insertBefore(this, top); }); break; case "AFTER": $("<div />").html(data).contents().each(function () { update.appendChild(this); }); break; default: $(update).html(data); break; } }); } //主要函数 //绑定的对象和参数 function asyncRequest(element, options) { var confirm, loading, method, duration; confirm = element.getAttribute("data-ajax-confirm"); if (confirm && !window.confirm(confirm)) { return; } loading = $(element.getAttribute("data-ajax-loading"));// duration = element.getAttribute("data-ajax-loading-duration") || 0;//默认是0 $.extend(options, { type: element.getAttribute("data-ajax-method") || undefined, url: element.getAttribute("data-ajax-url") || undefined, beforeSend: function (xhr) {//ajax前触发,此处的xhr将在下面用apply传递出去 var result; asyncOnBeforeSend(xhr, method);//判断是否添加特种的提交方式 result = getFunction(element.getAttribute("data-ajax-begin"), ["xhr"]).apply(this, arguments);//argument:替换函数对象的其中一个属性对象,存储参数。这里是将原先的参数传递出去,吊! if (result !== false) { loading.show(duration); } return result; }, complete: function () { loading.hide(duration); getFunction(element.getAttribute("data-ajax-complete"), ["xhr", "status"]).apply(this, arguments); }, success: function (data, status, xhr) { asyncOnSuccess(element, data, xhr.getResponseHeader("Content-Type") || "text/html"); getFunction(element.getAttribute("data-ajax-success"), ["data", "status", "xhr"]).apply(this, arguments); }, error: getFunction(element.getAttribute("data-ajax-failure"), ["xhr", "status", "error"]) }); options.data.push({ name: "X-Requested-With", value: "XMLHttpRequest" }); method = options.type.toUpperCase();//大写 if (!isMethodProxySafe(method)) { options.type = "POST"; options.data.push({ name: "X-HTTP-Method-Override", value: method }); } //最后都是调用jquery的ajax $.ajax(options); } function validate(form) { //可以取消验证 var validationInfo = $(form).data(data_validation); return !validationInfo || !validationInfo.validate || validationInfo.validate(); } $(document).on("click", "a[data-ajax=true]", function (evt) { evt.preventDefault(); asyncRequest(this, { url: this.href, type: "GET", data: [] }); }); $(document).on("click", "form[data-ajax=true] input[type=image]", function (evt) {//这个不常用 var name = evt.target.name, $target = $(evt.target), form = $target.parents("form")[0], offset = $target.offset(); $(form).data(data_click, [ { name: name + ".x", value: Math.round(evt.pageX - offset.left) }, { name: name + ".y", value: Math.round(evt.pageY - offset.top) } ]); setTimeout(function () { $(form).removeData(data_click); }, 0); }); $(document).on("click", "form[data-ajax=true] :submit", function (evt) { var name = evt.target.name, form = $(evt.target).parents("form")[0]; $(form).data(data_click, name ? [{ name: name, value: evt.target.value }] : []); setTimeout(function () { $(form).removeData(data_click); }, 0); }); $(document).on("submit", "form[data-ajax=true]", function (evt) { var clickInfo = $(this).data(data_click) || []; evt.preventDefault(); if (!validate(this)) { return; } asyncRequest(this, { url: this.action, type: this.method || "GET", data: clickInfo.concat($(this).serializeArray())//写得好,序列化表单并拼接,以后的ajax都可以这样,方便啊 }); }); }(jQuery));
jquery.unobtrusive-ajax.js单独的用法
- 非Core中的请参照:
MVC的验证 jquery.validate.unobtrusive
- Core中执行
页面引入相关JS:
<script src="~/lib/jquery/dist/jquery.js"></script> <script src="~/lib/jquery-validation/dist/jquery.validate.js"></script> <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script> <script src="~/lib/jquery-ajax-unobtrusive/dist/jquery.unobtrusive-ajax.js"></script>
向动态表单添加客户端验证
AddInfo.cshtml内容如下:
@model BasicFramework.Service.Implementation.Company_AddInfoRQ @{ Layout = "~/Views/Shared/_LayoutModal.cshtml"; } @section modalName{ @L["Add Info"] } <form asp-action="AddInfo" data-ajax="true" data-ajax-mode="replace" data-ajax-update="#Modal" data-ajax-success="reLoadModal" data-ajax-method="Post" class="form-horizontal"> <div class="toolbar"> @Html.Action("Index", "Toolbar") </div> <div asp-validation-summary="@ValidationSummary.All" style="color:red" id="validation_day" class="form-group"> <span style="color:blue">This is my message</span> </div> <div class="form-group"> <label asp-for="Code" class="control-label col-md-2"></label> <div class="col-md-10"> <input asp-for="Code" class="form-control required" /> <span asp-validation-for="Code" style="color:red"></span> </div> </div> <div class="form-group"> <label asp-for="Name" class="control-label col-md-2" style="color:blue"></label> <div class="col-md-10"> <input asp-for="Name" class="form-control" /> <span asp-validation-for="Name" style="color:red"></span> </div> </div> <div class="modal-footer"> <input type="submit" value="Create" class="btn btn-primary" /> </div> </form>
Index.cshtml调用页面代码:
function Add() { $.get({ url: "/Company/AddInfo", dataType: "html", error: function (jqXHR, textStatus, errorThrown) { alert(textStatus + ": Couldn't add form. " + errorThrown); }, success: function (r) { $("#Modal").html(r); //$("#Modal").find(".modal-dialog").addClass("modal-full"); var form = $("#Modal form"); //form.removeData("validator"); /* added by the raw jquery.validate plugin */ //form.removeData("unobtrusiveValidation"); /* added by the jquery unobtrusive plugin*/; $.validator.unobtrusive.parse(form); $("#Modal").modal(); } }); }
$.validator.unobtrusive.parse()
方法采用 jQuery 选择器作为它的一个参数。 此方法指示 jQuery 非介入式验证分析该选择器内表单的 data-
属性。 这些属性的值随后传递到 jQuery Validate 插件中,以便表单展示所需的客户端验证规则。
向动态控件添加客户端验证
也可以在动态生成各个控件(比如 <input/>
和 <select/>
)时,更新表单上的验证规则。 不能将用于这些元素的选择器直接传递到 parse()
方法,因为周围表单已进行分析并且不会更新。 应当先删除现有的验证数据,然后重新分析整个表单,如下所示:
$.get({ url: "https://url/that/returns/a/control", dataType: "html", error: function(jqXHR, textStatus, errorThrown) { alert(textStatus + ": Couldn't add control. " + errorThrown); }, success: function(newInputHTML) { var form = document.getElementById("my-form"); form.insertAdjacentHTML("beforeend", newInputHTML); $(form).removeData("validator") // Added by jQuery Validate .removeData("unobtrusiveValidation"); // Added by jQuery Unobtrusive Validation $.validator.unobtrusive.parse(form); } })
MVC内置的验证种类:
1.[Required] : 必须输入
[Required(ErrorMessage = "请输入用户名")]
2.[StringLength] : 限制字符串长度
[StringLength(10, ErrorMessage = "长度不能超过10个字符")]
3.[Range] : 限制取值范围
[Range(0, 120, ErrorMessage = "年龄范围在0到120岁之间")]
4.[RegularExpression] : 必须符合某个正则表达式(1)直接使用RegularExpression来写表达式:
[RegularExpression(@"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$", ErrorMessage = "请输入Email格式")] public String RegualarExpressionField { get; set; }
(2)自定义特性:
public class EmailAttribute : RegularExpressionAttribute { public EmailAttribute() :base(@"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$") { } }
5.Compare 判等比较
public class EmailAttribute : RegularExpressionAttribute { public EmailAttribute() :base(@"^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$") { } }
6.Remote : Ajax远程验证,返回值是bool类型 true表示验证通过
// Action方法 控制器类 请求方式 [Remote("User", "Validate", HttpMethod = "post", ErrorMessage = "用户名已经存在")] public string UserName { get; set; } //.... public ActionResult User() { //.. if(true) { return Json(true,JsonRequestBehavior.AllowGet); } else return Json(false,JsonRequestBehavior.AllowGet); }
7.OutputCache 页面缓存
[OutputCache(Duration=20)]//设置页面绝对缓存 缓存时间为 20秒 public ActionResult Index() { //详细代码 }