(是时候开发属于本身的插件了)数据校验插件开发指南

在看完了《JavaScript插件编写指南》以后,最激动人心的时刻到了!咱们着手开始作一个数据校验插件吧!javascript

咱们先初始化一个HTML用来做为校验的数据来源html

<body>
    <div>
        <form>
            <div>
                <label for="exampleInputEmail1">邮箱</label>
                <input type="email" id="exampleInputEmail1" placeholder="请输入合法邮箱">
            </div>
            <div>
                <label for="exampleInputPassword1">手机号码</label>
                <input type="text" id="exampleInputPhone1" placeholder="请输入合法手机号码">
            </div>
            <div>
                <label for="exampleInputPassword1">密码</label>
                <input type="password" id="exampleInputPassword1" placeholder="请输入有效密码">
            </div>
            <div>
                <label for="exampleInputPassword2">确认密码</label>
                <input type="password" id="exampleInputPassword2" placeholder="请再次输入密码">
            </div>

            <button type="submit">注册</button>
        </form>
    </div>
    <script src="jquery2.2.4.js"></script>
    <script src="dataValidate.js"></script>
</body>
复制代码

首先初始化插件

(function(root, factory, plug){
    // 工厂函数,用来当即执行下面的function,同时传入jquery对象和插件名称
    factory($,plug)
    // this在非严格模式的全局下表明window对象
})(this, function($,plug){
    // 测试是否成功调用了工厂函数
    console.log(plug);
},"dataValidate")
复制代码

由于咱们是依赖jQuery而开发的插件,因此咱们须要把咱们的插件绑定在jQuery实对象上,即绑定到jQuery的原型上去。java

(function(root, factory, plug) {
    factory($, plug)
})(this, function($, plug) {
    // 在jQuery中扩展dataValidate方法
    $.prototype[plug] = function() {

    }
}, "dataValidate")
复制代码

咱们能够在HTML上测试jQuery中是否成功绑定了这个属性jquery

<script> console.log($().dataValidate) </script>
复制代码

对表单校验进行限制

因为咱们的插件只是针对form表单中的input进行校验,并不会对全部的input的值进行校验,因此咱们接下来须要作一个限制:git

(function(root, factory, plug) {
    factory($, plug)
})(this, function($, plug) {
    $.prototype[plug] = function() {
        // this 表明的是jquery的实对象
        // 若是不在form中,则直接return出去,不进行校验
        if (!this.is("form")) {
            return;
        }
    }
}, "dataValidate")
复制代码

接下来,咱们知道,咱们须要对input进行校验,因此要找到form下面的全部input,并把它绑定到jQuery的一个属性上:github

(function(root, factory, plug) {
    factory($, plug)
})(this, function($, plug) {
    $.prototype[plug] = function() {
        if (!this.is("form")) {
            return;
        }
        // 将全部input绑定到jquery的$file中
        this.$file = this.find("input");
        // 对全部的input绑定一个input事件
        this.$file.on("input", function() {
            // 进行测试
            // 在事件函数里面,this表明触发这个事件的element对象(即这个this)
            // 在构造函数里,this表明的是这个构造函数的实对象
            console.log(this.value)
        })
    }
}, "dataValidate")
复制代码

若内置校验规则不知足用户需求,用户应能够自定义校验

可是这个时候,我有一个问题,这个input事件确定不能知足全部人的需求,由于这个插件是为了团队和用户开发的,用户可能须要一个blur事件来进行触发,这个时候该怎么作?npm

==================================解疑======================================== 这个input事件确定不能写死,这个时候咱们就须要用到默认配置,将不肯定的因素利用默认配置代替。框架

(function(root, factory, plug) {
    factory($, plug)
})(this, function($, plug) {
    // 存储默认配置
    var DAFAULT = {
        initEvent: "input"
    }
    $.prototype[plug] = function() {
        if (!this.is("form")) {
            return;
        }
        this.$file = this.find("input");
        // 可是问题又来了,难道就这么写DAFAULT.initEvent吗?
        this.$file.on(DAFAULT.initEvent, function() {})
    }
}, "dataValidate")
复制代码

其实咱们也可使用另一种方式,首先我会想个办法,我会把我默认配置里面的这些参数和属性所有扩展到另一个对象上面去------this,由于this表明了jQuery的实对象,我会把这默认配置都扩展到jQuery的实对象上,谁使用我,我就把这些属性扩展到谁身上去。函数

那么,怎么进行扩展呢? 其实jQuery已经给咱们准备好了,这个时候就用到了$.extend()这个方法,这个东西实现其实很简单,之后有空解读实现过程,如今大家知道他的用法就好了。测试

(function(root, factory, plug) {
    factory($, plug)
})(this, function($, plug) {
    var DAFAULT = {
        initEvent: "input"
    }
    $.prototype[plug] = function() {
        if (!this.is("form")) {
            return;
        }
        this.$file = this.find("input");
        $.extend(this, DAFAULT);
        // 进行测试
        console.log(this.initEvent) // input
        this.$file.on(this.initEvent, function() {})
    }
}, "dataValidate")
复制代码

使用了默认配置,可是还有一个问题,用户怎么使用他本身的配置呢?

固然是用户要用什么,就本身传什么。

<script> $("form").dataValidate({ // 用户怎么知道initEvent呢? // 那就是经过插件的接口文档来告诉用户,这个字段是配置触发事件的 initEvent: "blur" }) </script>
复制代码
(function(root, factory, plug) {
    factory($, plug)
})(this, function($, plug) {
    var DAFAULT = {
        initEvent: "input"
    }
    // 接收传过来的用户配置参数
    $.prototype[plug] = function(options) {
        if (!this.is("form")) {
            return;
        }
        this.$file = this.find("input");
        // 直接进行扩展
        $.extend(this, DAFAULT, options);
        // 进行测试
        console.log(this.initEvent) // input
        this.$file.on(this.initEvent, function() {})
    }
}, "dataValidate")
复制代码

在这个问题解决以后,咱们要开始思考一系列的问题,例如,咱们须要给这个插件提供基础的默认规则。

数据校验插件咱们须要提供如下基础的一些功能:

  1. 正则(reg)
  2. 输入不能为空(required)
  3. 长度最小值(min-length)
  4. 文本一致(confirm)
  5. 提示 (-message)
  6. 扩展用户自定义配置

明白了这些基础功能以后,咱们就在HTML里将规则先补上,

咱们能够经过配置自定义属性(data-)(也叫作指令)的方式来进行配置:

可是咱们要清楚哪些是咱们的配置,哪些是这个标签扩展的自定义属性,若是都是以data开头,那就没法区分是配置仍是扩展的自定义属性,因此这个时候要加个标签来代表这是个人插件配置dv,因此在接口文档里面,也要告诉用户经过data-dv来进行配置

<form>
    <div>
        <label for="exampleInputEmail1">邮箱</label>
        <!-- 不能为空 邮箱正则 -->
        <input type="email" id="exampleInputEmail1" placeholder="请输入合法邮箱" data-dv-required=true data-dv-required-message="邮箱不能为空" data-dv-reg="^\w+@\w+\.\w+$" data-dv-reg-message="邮箱格式不正确">
    </div>
    <div>
        <label for="exampleInputPassword1">手机号码</label>
        <!-- 不能为空 手机号正则 -->
        <input type="text" id="exampleInputPassword1" placeholder="请输入合法手机号码" data-dv-required=true data-dv-required-message="手机号码不能为空" data-dv-reg="^1\d{10}$" data-dv-reg-message="手机号码格式不正确">
    </div>
    <div>
        <label for="exampleInputPassword1">密码</label>
        <!-- 不能为空 密码正则 字符长度 -->
        <input type="password" id="exampleInputPassword1" placeholder="请输入有效密码" data-dv-required=true data-dv-required-message="密码不能为空" data-dv-reg="^\w+$" data-dv-reg-message="密码格式不正确" data-dv-min-length=6 data-dv-min-length-message="密码长度不正确">
    </div>
    <div>
        <label for="exampleInputPassword1">确认密码</label>
        <!-- 不能为空 密码一致 -->
        <input type="password" id="exampleInputPassword1" placeholder="请再次输入密码" data-dv-required=true data-dv-required-message="密码不能为空" data-dv-confirm=true data-dv-confirm-message="两次密码不一致">
    </div>
</form>
复制代码

配置完了以后,你会发现,咱们配置的这些玩意好像并无什么用,因此下面咱们就须要根据页面上的配置在js里面来写相应的默认规则。

(function(root, factory, plug) {
    factory($, plug)
})(this, function($, plug) {
    var DAFAULT = {
        initEvent: "input"
    }
    // 默认规则
    var RULES = {
        "reg": function() {},
        "required": function() {},
        "min-length": function() {},
        "confirm": function() {}
    }
    // 接收传过来的用户配置参数
    $.prototype[plug] = function(options) {
        if (!this.is("form")) {
            return;
        }
        this.$file = this.find("input");
        $.extend(this, DAFAULT, options);
        this.$file.on(this.initEvent, function() {
            // 遍历默认配置
            $.each(RULES, function(key, fn) {
                // 这个时候this指的是element对象
                // 咱们想用this.data来获取data上面用户自定义的属性,可是这个方法只有jQuery对象才拥有,这个时候该怎么办?
            });
        })
    }
}, "dataValidate")
复制代码

其实很简单,包装一下就能够了,将element对象包装成jQuery对象。

(function(root, factory, plug) {
    factory($, plug)
})(this, function($, plug) {
    var DAFAULT = {
        initEvent: "input",
        plugName: "dv"
    }
    // 默认规则
    var RULES = {
        "reg": function() {},
        "required": function() {},
        "min-length": function() {},
        "confirm": function() {}
    }
    // 接收传过来的用户配置参数
    $.prototype[plug] = function(options) {
        if (!this.is("form")) {
            return;
        }
        this.$file = this.find("input");
        $.extend(this, DAFAULT, options);
        this.$file.on(this.initEvent, function() {
            // 包装
            var _this = $(this);
            $.each(RULES, function(key, fn) {
                // _this.data("dv-" + key) 这样作有点傻,因此在默认配置里,写上dv
                var $fileName = _this.data(this.plugName + "-" + key);
                var $fileMessage = _this.data(this.plugName + "-" + key + "-message");
                // 测试一下输出的内容
                console.log($fileName);
                console.log($fileMessage);
            });
        })
    }
}, "dataValidate")
复制代码

接下来咱们须要用到call来调用函数,而且改变this指向

作个测试:

var RULES = {
    "reg": function() {
        console.log(this);
    },
    "required": function() {
        console.log(this);
    },
    "min-length": function() {
        console.log(this);
    },
    "confirm": function() {
        console.log(this);
    }
}
复制代码
$.each(RULES, function(key, fn) {
    var $fileName = _this.data(this.plugName + "-" + key);
    var $fileMessage = _this.data(this.plugName + "-" + key + "-message");
    if ($fileName) {
        // fn.call()
        // fn.call(this)
        fn.call(_this)
    }
});
复制代码

看明白了this的指向以后,咱们就要开始着手完成默认的校验规则

var RULES = {
    "reg": function(data) {
        return new RegExp(data).test(this.val());
    },
    "required": function(data) {
        return this.val();
    },
    "min-length": function(data) {
        return this.val().length > data;
    },
    "confirm": function(data) {
        // 思考一下密码一致的校验该怎么作?
    }
}
复制代码
$.each(RULES, function(key, fn) {
    var $fileName = _this.data(this.plugName + "-" + key);
    var $fileMessage = _this.data(this.plugName + "-" + key + "-message");
    if ($fileName) {
        var result = fn.call(_this, $fileName);
        if (!result) {
            // 进行报错处理
        }
    }
});
复制代码

校验是否一致能够这样作:

"confirm": function(data) {
    var passwordElement = $(":password")[0];
    if (passwordElement.value == "" || this.val() != passwordElement.value) {
        return false;
    } else {
        return true;
    }
}
复制代码

最后一步,进行报错处理:

this.$file.on(this.initEvent, function() {
    var _this = $(this);
    // 监测是否已经有报错信息,若是有,就全干掉
    _this.siblings('p').remove();
    $.each(RULES, function(key, fn) {
        var $fileName = _this.data(this.plugName + "-" + key);
        var $fileMessage = _this.data(this.plugName + "-" + key + "-message");
        if ($fileName) {
            var result = fn.call(_this, $fileName);
            if (!result) {
                // 直接在后面追加报错信息
                _this.after("<p style='color:red'>" + $fileMessage + "</p>")
            }
        }
    });
})
复制代码

到了这一步基本上完成了,用户只须要引入咱们这个js文件,而后把接口文档交给用户,让用户自定义报错信息和正则校验就能够了。

可是,若是用户想要扩展本身的默认方法,即扩展默认校验规则,好比新增一个max-length,这个时候该怎么办?

按照咱们的这种方式,大家以为可以进行扩展吗?

固然能够,由于咱们的方法绑定在jQuery实对象上面,因此就可使用jQuery的扩展方法的方式进行扩展,而且要告诉用户用这种方式进行扩展

$.fn.dataValidate.extendValidate = function(options) {
    $.extend(RULES, options)
}
复制代码
<script type="text/javascript"> // 用户扩展  $.fn.dataValidate.extendValidate({ "max-length": function(data) { return this.val().length <= data; } }) </script>
复制代码

咱们能够配置data-dv-max-length来进行测试。

至此,一个简单的数据校验插件已经开发完成。

总结

咱们开发一个需求或者解决一个问题以前,多想一想该如何改才会使代码复用性更高,效率更快,而不是一上手就不假思索的用if{}else{}来进行判断修改,这样代码量多了以后,维护起来就很麻烦了。

而咱们这种形式的代码,进行数据校验总比每次校验都使用if{}else{}的代码好上千百倍,可维护性,可扩展性都比较好,固然这种代码也不是一朝一夕就能写出来的,须要日积月累。

最后,你们一块儿加油吧。

最后很差意思推广一下我基于 Taro 框架写的组件库:MP-ColorUI

能够顺手 star 一下我就很开心啦,谢谢你们。

点这里是文档

点这里是 GitHUb 地址

相关文章
相关标签/搜索