基于h5表单验证系统、扩展了对easyui组件的支持
先上图:
提示样式用到了伪对象的 {content: attr(xxx)}函数方法,实现提示信息能动态切换。
1、关键属性说明:
type: 表单元素类型(h5的input类型:number、email等),
max: type为number、range时可用的属性,
min: type为number、range时可用的属性,
pattern: 正则表达式,
maxLength: 元素最大长度,
placeholder: 输入域的填写提示,
required: 必填
required-msg: 为空时的校验提示,
invalid-msg: 正则校验不通过的提示(对应pattern的校验规则)
2、demo - html:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>javascript test</title> <link rel="stylesheet" type="text/css" href="css/metro/easyui.css"> <link rel="stylesheet" type="text/css" href="css/icon.css"> <link rel="stylesheet" type="text/css" href="css/demo.css"> <script type="text/javascript" src="js/jquery.min.js"></script> <script type="text/javascript" src="js/valid.js"></script> <script type="text/javascript" src="js/jquery.easyui.min.js"></script> <style> .hidden{ display: none; } /* 表单校验样式 */ .valid-item { display: inline-block; position: relative; } .valid-item:after { content: attr(data-msg); position: absolute; top: calc(100% + 2px); left: 0; color: #cc0066; font-size: 10px; opacity: 0; transition: opacity 0.5s ease; text-shadow: 1px 1px 5px silver; z-index: -1; } .valid-item.invalid:after { opacity: 1; z-index: 100; } </style> </head> <body> <div class="middle"> <h5> <pre> 表单校验:$(form).cform('valid'); </pre> <pre> 表单提交:$(form).cform('submit',fn); </pre> </h5> <form class="easyui-cform" action="index.do" method="post"> <h5>第一种纯容器模式:根据type生成对应的表单元素</h5> <span class="valid-item" name="name" invalid-msg="字母、数字,以字母开头且最少3位" type="text" maxLength="4" value="sr" required pattern="^[a-zA-Z_][a-zA-Z0-9_@.]{2,16}$" placeholder="字母、数字"> <!-- <input id="name" type="text" name="name" value="sc" required pattern="^[a-zA-Z_][a-zA-Z0-9_]{2,16}$" placeholder="字母、数字" class="ignore"/> --> </span> <br> <br> <h5>第二种非纯容器模式:子节点已经包含表单元素,将不再生成新的表单元素,子节点按h5的表单属性配置</h5> <span class="valid-item" required-msg="必填项"> <select name="sex" required style=" 170px;"> <option value="">--select--</option> <option value="1">man</option> <option value="2">women</option> </select> </span> <h5>非纯容器模式:easyui-numberbox组件解析</h5> <span class="valid-item" required-msg="数字必填项"> <input class="easyui-numberbox" name="phone" required style=" 170px;"> </span> <h5>非纯容器模式:easyui-combobox组件解析</h5> <span class="valid-item" name="country" required-msg="必填项"> <input id="cc" class="easyui-combobox" required data-options=" valueField: 'label', textField: 'value', data: [{ label: '', value: 'select' },{ label: 'java', value: 'Java' },{ label: 'perl', value: 'Perl' },{ label: 'ruby', value: 'Ruby' } ]" /> </span> <input type="submit" value="submit"> </form> </div> </body> </html>
3、valid.js:
function easyuiInvalidProcess(item, value) { item.parentNode.classList.add('invalid'); var $pnode = $(item.parentNode), requiredMsg = $pnode.attr('required-msg') || $.fn.cform.defaults.required, invalidMsg = $pnode.attr('invalid-msg') || $.fn.cform.defaults.invalid; if (value) { item.parentNode.classList.remove('invalid'); $pnode.attr('data-msg', ''); } else $pnode.attr('data-msg', requiredMsg); } (function($) { function _initItem(form) { /* 初始化校验容器 */ var ctns = $('.valid-item', form).not('.hasparsed'); ctns.each(function(index, item) { var $item = $(item), props = { id: $item.prop('id') ? $item.prop('id') + '_input' : undefined, name: $item.attr('name'), value: $item.attr('value'), type: $item.attr('type') || 'text', max: $item.attr('max'), min: $item.attr('min'), pattern: $item.attr('pattern'), maxLength: $item.attr('maxLength'), placeholder: $item.attr('placeholder'), required: $item.attr('required') || $item.attr('required') }, propstr = ' '; $.each(props, function(key, value) { if (value) propstr += key + '=' + value + ' '; }); var itemChilds = $item.children(), noChild = itemChilds.length == 0; if (noChild) { /* 校验容器如果没有子节点则生成type对应的表单元素 */ var $input = $('<input ' + propstr + '/>'); $(this).append($input); item.removeAttribute('name'); } else { itemChilds.each(function(n, child) { var isEasyui = $(child).prop('class').indexOf('easyui-') >= 0; if (isEasyui) { /* easyui组件初始化 */ $.each(props, function(key, value) { if (value) $(child).attr(key, value); }); $(child).addClass('ignore'); item.removeAttribute('name'); var options = $(child).data('options') || ''; if (options) { options += ',onChange:function(val,oval){ easyuiInvalidProcess(this, val); }'; } else { options += 'onChange:function(val,oval){ easyuiInvalidProcess(this, val); }'; } $(child).attr('data-options', options); /* 解决报错:An invalid form control with name='' is not focusable */ $(child).removeAttr('required'); } }); } ctns.addClass('hasparsed'); }); } function itemInvalidProcess(item) { item.setCustomValidity(' '); item.parentNode.classList.add('invalid'); var $pnode = $(item.parentNode), requiredMsg = $pnode.attr('required-msg') || $.fn.cform.defaults.required, invalidMsg = $pnode.attr('invalid-msg') || $.fn.cform.defaults.invalid; if (item.validity.valueMissing) $pnode.attr('data-msg', requiredMsg); else $pnode.attr('data-msg', invalidMsg); } function _initValid(form, op) { /* 初始化form及表单元素 */ if (form) { bindEvent(form); _initItem(form); var inputs = $(':input', form).not('.ignore'); inputs.map(function(index, item) { var $input = $(item); item.addEventListener('invalid', function() { itemInvalidProcess(this); }); item.addEventListener('input', function() { this.setCustomValidity(''); this.parentNode.classList.remove('invalid'); if (!this.validity.valid) { /* this.validity h5表单元素的校验结果对象 */ itemInvalidProcess(this); } }); }); form.addEventListener('submit', function() { /* 校验通过时执行 */ console.log(123); }); }; } function bindEvent(form) { /* 关掉浏览器默认行为 */ var $form = $(form); $form.data('submit', form.submit); form.submit = function(event) { var valid = validCheck(form); if (valid) $form.data('submit').call(form); }; $form.on("invalid", "form", function(event) { event.preventDefault(); }); $form.on("click", "input[type=submit]", function(event) { var valid = validCheck(form); if (!valid) event.preventDefault(); }); } function validCheck(form) { /* 检查校验是否通过 */ var inputs = $(':input', form), valid = true; inputs.map(function(index, item) { var iCls = $(item).prop('class'); if (item.type != "submit" && !item.checkValidity() && iCls.indexOf( 'ignore') < 0) { valid = false; } else if (iCls.indexOf('textbox-value') >= 0) { /* 扩展easyui组件支持 */ var domCtn = $('[textboxname="' + $(item).attr('name') + '"]'), clist = domCtn[0].classList; $.each(clist, function(n, cls) { try { var pName = cls.replace('easyui-', ''), value = domCtn[pName]('getValue'); if (value) { } else valid = false; easyuiInvalidProcess(domCtn[0], value); } catch (e) {} }); } }); return valid; } $.fn.cform = function(options, param) { /* 判断是否为对外调用API */ if (typeof options == 'string') { return $.fn.cform.methods[options](this, param); } /* 初始化组件 */ var op = $.extend({}, $.fn.cform.defaults, options); return this.each(function() { _initValid(this, op) }); } $.fn.cform.methods = { valid: function(form, param) { var $inputs = $(':input', form) || []; for (var i = 0; i < $inputs.length; i++) { var input = $inputs[i]; if (input.type != "submit" && !input.validity.valid) { input.checkValidity(); return false; } } return true; }, submit: function(form, fn) { return form.each(function() { var url = form.prop('action'), dataType = 'json'; var valid = validCheck(form); if (valid) { try { var param = $(form).serializeJson(); $.post(url, param, function(data) { try { if (typeof fn == 'function') fn(data); } catch (e) {} }, dataType); } catch (e) {} } }); } } $.fn.cform.defaults = { required: 'field required !', invalid: 'field invalid !' } })(jQuery)
4、easyui-parser改动处:
$.parser = { auto: true, onComplete: function(_1) {}, plugins: ["draggable", "droppable", "resizable", "pagination", "tooltip", "linkbutton", "menu", "menubutton", "splitbutton", "cform", /* 为了让组件自动解析 */ "switchbutton", "progressbar", "tree", "textbox", "filebox", "combo", "combobox", "combotree", "combogrid", "numberbox", "validatebox", "searchbox", "spinner", "numberspinner", "timespinner", "datetimespinner", "calendar", "datebox", "datetimebox", "slider", "layout", "panel", "datagrid", "propertygrid", "treegrid", "datalist", "tabs", "accordion", "window", "dialog", "form" ],