【表单验证】基于jQuery的高度灵活的表单验证(无UI)

表单验证是前端开发过程中常见的一个需求,产品需求、业务逻辑的不同,表单验证的方式方法也有所区别。而最重要的是我们要清楚,表单验证的核心原则是——错误信息提示准确,并且尽可能少的打扰/干扰用户的输入和体验。

该插件依赖于jQuery,demo地址:点击

基于以上原则,个人总结出表单验证的通用方法论:

为了使开发思路更加清晰,我将表单验证的过程分为两步:第一步,用户输入完验证当前输入的有效性;第二步,表单提交时验证整个表单。考虑如下布局:


<form action="">
    <ul>
        <li><label for="username">用户名</label>
            <input type="text" name="username" id="username" placeholder="用户名"/></li>
        <li>
            <label for="password">密码</label>
            <input type="text" name="password" id="password" placeholder="密码"/>
        </li>
        <li>
            <label for="password">确认密码</label>
            <input type="text" name="password2" id="password-confirm" placeholder="确认密码"/>
        </li>
        <li>
            <label for="phone">手机</label>
            <input type="text" name="mobile" id="phone"/>
        </li>
        <li>
            <label for="email">邮箱</label>
            <input type="text" name="email" id="email"/>
        </li>
    </ul>

    <button type="submit" id="submit-btn">提交</button>

</form>


一个较为通用的JS验证版本如下:


(function (window, $, undefined) {
    /**
     *  @param  {String}        $el             表单元素
     *  @param  {[Array]}       rules           自定义验证规则
     *  @param  {[Boolean]}     isCheckAll      表单提交前全文验证
     *  @param  {[Function]}    callback        全部验证成功后的回调
     *  rules 支持四个字段:name, rule, message, equalTo
     */
    function Validator($el, rules, isCheckAll, callback) {
        var required = 'required';
        var params = Array.prototype.slice.call(arguments);
        this.$el = $el;
        this._rules = [
            {// 用户名
                username: required,
                rule: /^[\u4e00-\u9fa5\w]{6,12}$/,
                message: '不能包含敏感字符'
            }, {// 密码
                password: required,
                rule: /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z_@]{6,20}$/,
                message: '只支持数字字母下划线,且不为纯数字或字母'
            }, {// 重复密码
                password2: required,
                rule: /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z_@]{6,20}$/,
                message: '只支持数字字母下划线,且不为纯数字或字母',
                equalTo: 'password'
            }, {// 手机
                mobile: required,
                rule: /^1[34578]\d{9}$/,
                message: '请输入有效的手机号码'
            }, {// 验证码
                code : required,
                rule: /^\d{6}$/,
                message: '请输入6位数字验证码'
            }, {// 邮箱
                email : required,
                rule: /^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/,
                message: '请输入正确的邮箱'
            }
        ];
        this.isCheckAll = false;
        this.callback = callback;
        // 合并参数
        this._rules = this._rules.concat(params[1]);
        if(params[2]) {
            if(typeof params[2] == 'function') {
                this.callback = params[2];
            }else {// 提交表单时是否开启全部验证
                this.isCheckAll = params[2];
            }
        }
        // 用于存储合去重后的参数
        this.rules = [];
    }

    Validator.prototype._getKey = function (obj) {
        var k = '';
        for(var key in obj) {
            if(obj.hasOwnProperty(key)) {
                if( key !== 'rule' && key !== 'message' && key !== 'equalTo') {
                    k = key;
                }
            }
        }
        return k;
    };
    /**
     * 数组对象重复数据进行合并,后面的覆盖前面的
     */
    Validator.prototype.filterRules = function (arrObj) {
        var _this = this,
            h = {},
            res = [],
            arrObject = this._rules;
        $.each(arrObject, function (i, item) {
            var k = _this._getKey(item);
            try {
                if(!h[k] && h[k] !== 0) {
                    h[k] = i;
                    res.push(item);
                }else {
                    res[h[k]] = $.extend(res[h[k]], item);
                }
            }catch(e) {
                throw new Error('不是必填')
            }
        });
        this.rules = res;
    };

    Validator.prototype.check = function () {
        var _this = this;
        $.each(_this.rules, function (i, item) {
            var key = _this._getKey(item),
                reg = item.rule,
                equalTo = item.equalTo,
                errMsg = item.message;

            _this.$el.find('[name='+key+']')
                .on('blur', function () {
                    var $this = $(this),
                        errorMsg = '',
                        val = $this.val(),
                        ranges = reg.toString().match(/(\d*,\d*)/),
                        range = '',
                        min = 0,
                        max = 0,
                        placeholderTxt = $(this).attr("placeholder") ? $(this).attr("placeholder") : '信息';

                    // 定义错误提示信息
                    if(val && val != 'undefined') { // 值不为空

                        if(ranges) { // 边界限定
                            range = ranges[0];
                            min = range.split(',')[0] ? range.split(',')[0].trim() : 0;
                            max = range.split(',')[1] ? range.split(',')[1].trim() : 0;
                            if(val.length < min || val.length > max) { // 处理边界限定的情况
                                if(min && max) {
                                    errorMsg = '<span class="error-msg">请输入'+min+'-'+max+'位'+placeholderTxt+'</span>';
                                }else if(min) {
                                    errorMsg = '<span class="error-msg">最少输入'+min+'位'+placeholderTxt+'</span>';
                                }else if(max) {
                                    errorMsg = '<span class="error-msg">最多输入'+max+'位'+placeholderTxt+'</span>';
                                }
                            }else { // 边界正确但匹配错误
                                errorMsg = '<span class="error-msg">'+errMsg+'</span>';

                            }
                        }else { // 没有边界限定
                            errorMsg = '<span class="error-msg">'+errMsg+'</span>';
                        }

                        if(equalTo) {
                            var equalToVal = _this.$el.find('[name='+equalTo+']').val();
                            if(val !== equalToVal) {
                                errorMsg = '<span class="error-msg">两次输入不一致,请重新输入</span>';
                            }
                        }

                    } else { // 值为空
                        errorMsg = '<span class="error-msg">请输入'+placeholderTxt+'</span>'
                    }
                    if($('.error-msg').length > 0) return;

                    // 验证输入,显示提示信息
                    if(!reg.test(val) || (equalTo && val !== equalToVal)) {
                        if($this.siblings('.error-msg').length == 0) {
                            $this.after(errorMsg)
                                .siblings('.error-msg')
                                .hide()
                                .fadeIn();
                        }
                    }else {
                        $this.siblings('.error-msg').remove();
                    }
                })
                .on('focus', function () {
                    $(this).siblings('.error-msg').remove();
                })
        });

    };
    Validator.prototype.checkAll = function () {
        var _this = this;
        if(_this.isCheckAll) {
            _this.$el.find('[type=submit]')
                .click(function () {
                    _this.$el.find('[name]').trigger('blur');
                    if($('.error-msg').length > 0) {
                        console.log('有错误信息');
                        return false;
                    }else {
                        console.log('提交成功');
                        _this.callback();
                    }
                });
            return false;
        }
    };
    Validator.prototype.init = function () {
        this.filterRules();
        this.check();
        this.checkAll();
    };
    $.fn.validator = function (rules, isCheckAll, callback) {
        var validate = new Validator(this, rules, isCheckAll, callback);
        return validate.init();
    };
})(window, jQuery, undefined);

你可以这样使用:


    var rules = [
        {// 用户名
            username: 'required',
            rule: /^[\u4e00-\u9fa5\d]{6,12}$/,
            message: '只支持数字loo2222'
        },
        {// 密码
            password: 'required',
            rule: /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z_@]{6,20}$/,
            message: 'mimmimmia'
        },
        {// 重复密码
            password2: 'required',
            rule: /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z_@]{6,20}$/,
            message: '只支持数字字母下划线,不能为纯数字或字母2222',
            equalTo: 'password'
        },
        {// 座机
            telephone : 'required',
            rule: /^[A-Za-z0-9\u4e00-\u9fa5]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$/,
            message: '请输入正确的座机'
        }
    ];
    $('form').validator(rules, true)

posted @ 2017-03-22 13:15  Liaofy  阅读(253)  评论(0编辑  收藏  举报