Lenny-Hu / note

blog
5 stars 1 forks source link

js & vue表单验证插件 #71

Open Lenny-Hu opened 4 years ago

Lenny-Hu commented 4 years ago

vuelidate

https://github.com/vuelidate/vuelidate

Lenny-Hu commented 4 years ago

vee-validate

体积有点大

https://baianat.github.io/vee-validate/


import Vue from 'vue'
import VeeValidate, { Validator } from 'vee-validate'
import zh from 'vee-validate/dist/locale/zh_CN'// 引入中文文件
// 配置中文
Validator.addLocale(zh)
const config = {
  errorBagName: 'errors', // change if property conflicts.
  fieldsBagName: 'fieldBags',  // 报冲突时 可自定义修改字段名称
  delay: 0, // 错误提示的延迟时间
  strict: true, // 没有设置规则的表单不进行校验,
  enableAutoClasses: false,
  locale: 'zh_CN', // 对语言(中文)的配置
  classNames: {
    touched: 'touched', // the control has been blurred
    untouched: 'untouched', // the control hasn't been blurred
    valid: 'valid', // model is valid
    invalid: 'invalid', // model is invalid
    pristine: 'pristine', // control has not been interacted with
    dirty: 'dirty' // control has been interacted with
  },
  events: 'input', //* *input|blur** 在用户输入和表单失去焦点时都进行校验 可单独写  blur或input
  inject: true
}
Vue.use(VeeValidate, config)

// 自定义validate
const dictionary = {
  zh_CN: {
    messages: {
      email: () => '请输入正确的邮箱格式',
      required: (field) => '请输入' + field
    },
    attributes: {
      email: '邮箱',
      password: '密码',
      task_name: '任务名称',
      phone: '手机',
      task_type: '任务类型',
      task_template: '任务模板',
      task_tine_type: '时间类型',
      task_tine_value: '时间类型值',
      assisting_department: '协助单位',
      responsible_department: '责任单位',
      target_area: '目标新增面积',
      target_cahnge_number: '目标改造数量',
      implementation_plan: '实施方案',
      assessment_standard: '考核指标',
      grading_standard: '评分标准',
      score: '考核分值'
    }
  }
}

Validator.updateDictionary(dictionary)

Validator.extend('phone', {
  messages: {
    zh_CN: field => field + '必须是11位手机号码'
  },
  validate: value => {
    return value.length === 11 && /^((13|14|15|17|18)[0-9]{1}\d{8})$/.test(value)
  }
})

例如

// 先加载vue、vee-validate、zh-cn文件,再加载下列代码
// vee-validate 公共规则、设置
(function () {
  Vue.use(window.VeeValidate, {
    locale: 'zh_CN'
  }); // 使用vue插件

  // 自定义规则
  window.VeeValidate.Validator.extend('phone', {
    getMessage: function (field) {
      return field + '必须是11位号码';
    },
    validate: function (value) {
      return /^1[3-9]\d{9}$/.test(value);
    }
  });

  // 定义全局错误信息
  var dictionary = {
    zh_CN: {
      messages: {
        email: function () {
          return '请输入正确的邮箱';
        },
        required: function (field) {
          return '请输入' + field;
        }
      }
      // attributes: {
      //   mobile: '电话',
      //   address: '地址'
      // }
    }
  }
  window.VeeValidate.Validator.localize(dictionary);
})();
Lenny-Hu commented 4 years ago

validatejs

面向对象的数据检验插件

http://validatejs.org

https://github.com/ansman/validate.js

Lenny-Hu commented 4 years ago

jQuery html5Validate基于HTML5表单验证插件

https://l-ui.com/content/apis/validate.html https://www.zhangxinxu.com/wordpress/2012/12/jquery-html5validate-html5-form-validate-plugin/

Lenny-Hu commented 4 years ago

jQuery Validation

https://jqueryvalidation.org

Lenny-Hu commented 4 years ago

基于js | zeptojs简单的表单验证方法

html

<form class="js-form"> 
            <ul>     
                <li class="">
                    <div class="">
                        <input
                            type="text"
                            value=""
                            placeholder=""
                            name="realName"
                        >
                    </div>
                </li>
                <li class="">
                    <div class="">
                        <input type="text" value="" placeholder="请输入手机号" name="mobile">
                    </div>
                </li>
                <li class="">
                    <div class="">
                        <input type="text" value="" placeholder="请输入图形验证码" name="captcha">
                    </div>
                </li>
                <li class="sms-code">
                    <div class="">
                        <input type="text" value="" placeholder="请输入短信验证码" name="code">
                    </div>
                </li>
                <li class="check-box">
                    <div class="">
                        <input type="checkbox" name="checkbox" id="" value="checkbox1">
                        <input type="checkbox" name="checkbox" id="" value="checkbox2">
                        <input type="checkbox" name="checkbox" id="" value="checkbox3">
                        <input type="checkbox" name="checkbox" id="" value="checkbox4">
                    </div>
                </li>
                <li class="radio-box">
                    <div class="">
                        <input type="radio" name="radio" id="" value="radio1">
                        <input type="radio" name="radio" id="" value="radio2">
                        <input type="radio" name="radio" id="" value="radio3">
                    </div>
                </li>
                <li class="select-box">
                    <div class="">
                        <select name="select" id="" multiple>
                            <option value="option1">option1</option>
                            <option value="option2">option2</option>
                            <option value="option3">option3</option>
                        </select>
                    </div>
                </li>
                <li class="textarea-box">
                        <div class="">
                            <textarea name="textarea" id="" cols="30" rows="10"></textarea>
                        </div>
                </li>
                <li class="file-box">
                        <div class="">
                            <input type="file" name="file" id="">
                        </div>
                </li>
            </ul>
        </form>
  /**
   * 简单的表单验证器
   * @param {$元素对象} $box 表单的容器
   * @param {object} rules 验证规则
   */
  function Validator ($box, rules) {
    this.$box = $box;
    this.rules = rules;
    this.results = {
      valid: true, // 验证通过标识
      errors: [], // 错误列表
      data: {} // 表单数据
    };
  }

  // 处理错误消息
  Validator.prototype.handleMsg = function (eleData, rule, errMsg) {
    if (errMsg) {
      this.results.valid = false;
      var error = {
        name: eleData.name,
        label: rule.label,
        message: errMsg
      };
      this.results.errors.push(error);

      eleData.$ipts.addClass('invalid').parent().addClass('invalid-box');
    } else {
      eleData.$ipts.removeClass('invalid').parent().removeClass('invalid-box');
    }

    // 错误消息(错误消息可用css+伪元素方式显示在界面上)
    eleData.$ipts.parent().attr('data-invalid-msg', errMsg || '');
  }

  // 非空验证
  Validator.prototype.required = function (eleData, rule) {
    if (!rule.required) {
      return true;
    }
    var valid = false;

    // 根据不同类型的元素执行不同的检查方式
    switch (eleData.type) {
      case 'checkbox':
      case 'radio':

        eleData.$ipts.each(function (i, e) {
          valid = e.checked;
          return e.checked ? false : true;
        });

        break;
      default:

        valid = !!eleData.iptVal;

        break;
    }

    this.handleMsg(eleData, rule, valid ? '' : rule.label + '不能为空');
    return valid;
  }

  // 自定义正则检查
  Validator.prototype.test = function (eleData, rule) {
    if (!(Array.isArray(rule.patterns) && rule.patterns.length)) {
      return true;
    }
    var valid = false;
    var message = '';

    for (var j = 0; j < rule.patterns.length; j++) {
      var v = rule.patterns[j];
      valid = v.pattern.test(eleData.iptVal);

      message = valid ? '' : v.message
      if (!valid) {
        break;
      }
    }

    this.handleMsg(eleData, rule, message);
    return valid;
  }

  // 数据长度检查
  Validator.prototype.datalength = function (eleData, rule) {
    if (!rule.maxlength && !rule.minlength) {
      return true;
    }

    // 无需检查的元素
    if (['radio', 'select-one'].includes(eleData.type)) {
      return true;
    }

    var maxlength = rule.maxlength || Infinity;
    var minlength = rule.minlength || 0;
    var valid = false;
    var message = '';

    // 处理select和checkbox
    var handleMsg = function (count, type) {
      var msgMap = {
        option: {
          maxlength: rule.label + '最多选择' + maxlength + '项',
          minlength: rule.label + '最少选择' + minlength + '项'
        },
        text: {
          maxlength: rule.label + '最大长度应为' + maxlength + '位字符',
          minlength: rule.label + '最小长度应为' + minlength + '位字符'
        }
      };

      // 最大
      valid = maxlength >= count;
      if (!valid) {
        message = msgMap[type].maxlength;
        return false;
      }

      // 最小
      valid = count >= minlength;
      if (!valid) {
        message = msgMap[type].minlength;
        return false;
      }
    }

    switch (eleData.type) {
      case 'checkbox':

        var checkedCount = 0;
        eleData.$ipts.each(function (i, e) {
          e.checked && checkedCount++;
        });
        handleMsg(checkedCount, 'option');

        break;

      case 'select-multiple':

        var selectedCount = eleData.$ipts[0].selectedOptions.length;
        handleMsg(selectedCount, 'option');

        break;

      case 'file':

        var files = eleData.$ipts[0].files;
        // ie9等没有files属性的浏览器忽略
        if (!files) {
          valid = true;
        } else {
          for (var index = 0; index < files.length; index++) {
            var item = files[index];
            // 只检查文件的最大大小
            valid = maxlength >= item.size;
            if (!valid) {
              message = rule.label + '文件最大限制大小为' + (maxlength / 1024) + 'KB';
              break;
            }
          }
        }
        break;

      default:

        handleMsg(eleData.iptVal.length, 'text');

        break;
    }

    this.handleMsg(eleData, rule, message);
    return valid;
  }

  // 文件后缀名检查
  Validator.prototype.suffix = function (eleData, rule) {
    if (!(Array.isArray(rule.suffixs) && rule.suffixs.length)) {
      return true;
    }

    // 无需检查的元素
    if (eleData.type != 'file') {
      return true;
    }

    var valid = false;

    valid = rule.suffixs.some(function (v, i) {
      return eleData.iptVal.endsWith(v);
    });

    this.handleMsg(eleData, rule, valid ? '' : rule.label + '文件后缀只能是' + rule.suffixs.join('、'));
    return valid;
  }

  // 数字大小范围检查
  Validator.prototype.range = function (eleData, rule) {
    if (!rule.min && !rule.max) {
      return true;
    }

    // 无需检查的元素
    if (!['text', 'number'].includes(eleData.type)) {
      return true;
    }

    var valid = false;
    var message = '';
    var max = rule.max || Infinity;
    var min = rule.min || -10000 * 10000;
    var number = parseFloat(eleData.iptVal);

    if ((valid = isNaN(number))) {
      message = rule.label + '不是一个合法的数字';
    } else {
      valid = max >= number;
      if (!valid) {
        message = rule.label + '最大应该为' + max;
      }

      valid = number >= min;
      if (!valid) {
        message = rule.label + '最小应该为' + min;
      }
    }

    this.handleMsg(eleData, rule, message);
    return valid;
  }

  // 添加合法的数据
  Validator.prototype.pushData = function (eleData) {
    var data = [];

    switch (eleData.type) {
      case 'checkbox':
      case 'radio':

        eleData.$ipts.each(function (i, e) {
          if (e.checked) {
            data.push(e.value);
          }
        });

        break;

      case 'select-one':
      case 'select-multiple':

        for (var index = 0; index < eleData.$ipts[0].selectedOptions.length; index++) {
          var e = eleData.$ipts[0].selectedOptions[index];
          data.push(e.value);
        }

        break;

      case 'file':

        this.results.data[eleData.name] = eleData.$ipts[0].files;
        return true;

        break;

      default:

        data.push(eleData.iptVal);

        break;
    }

    this.results.data[eleData.name] = data.join(',');
  }

  // 检查
  Validator.prototype.validate = function () {
    for (var key in this.rules) {
      console.log(key);
      if (!this.rules.hasOwnProperty(key)) {
        continue;
      }

      var rule = this.rules[key];
      var $ipts = this.$box.find('[name="' + key + '"]');

      if (!$ipts.length) {
        continue;
      }

      var eleData = {
        name: key,
        nodeName: $ipts[0].nodeName.toLowerCase(),
        type: $ipts.attr('type').toLowerCase(),
        iptVal: $.trim($ipts.val()),
        $ipts: $ipts
      };

      // 非空
      if (!this.required(eleData, rule)) {
        continue;
      }

      // 长度和大小
      if (!this.datalength(eleData, rule)) {
        continue;
      }

      // 大小范围
      if (!this.range(eleData, rule)) {
        continue;
      }

      // 文件后缀检查
      if (!this.suffix(eleData, rule)) {
        continue;
      }

      // 自定义规则
      if (!this.test(eleData, rule)) {
        continue;
      }

      // 将合法数据添加到data
      this.pushData(eleData);
    }
    return this.results;
  }

使用

var rules = {
        realName: {
            label: '真实姓名',
            required: true
        },
        mobile: {
            label: '手机号',
            required: true,
            patterns: [
                {
                    pattern: /^1[3-9]\d{9}$/,
                    message: '请输入合法的手机号'
                }
            ]
        },
        captcha: {
            label: '图形验证码',
            required: true,
            max: 4,
            min: 1
        },
        code: {
            label: '短信验证码',
            required: true,
            maxlength: 4,
            minlength: 4
        },
        checkbox: {
            label: 'checkbox',
            required: true,
            maxlength: 3
        },
        radio: {
            label: 'radio',
            required: true
        },
        select: {
            label: 'select',
            required: true,
            minlength: 2
        },
        textarea: {
            label: 'textarea',
            required: true,
            minlength: 10,
            maxlength: 20
        },
        file: {
            label: 'file',
            required: true,
            maxlength: 1024 * 1024,
            suffixs: ['zip', 'docx']
        }
    };

var validateRes = (new validator(self.$el.find('.js-form'), rules)).validate();
console.log(validateRes);