jquery plugin 之 form表单验证插件

基于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="width: 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="width: 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>
View Code

 

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)
View Code

 

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"
    ],

 

posted @ 2018-02-11 15:57  【云】风过无痕  阅读(228)  评论(0编辑  收藏  举报