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

栏目: jQuery · 发布时间: 6年前

内容简介:在看完了首先,我们先初始化一个HTML用来作为校验的数据来源因为我们是依赖

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

首先,我们先初始化一个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 的原型上去。

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

    }
}, "dataValidate")
复制代码

我们可以在HTML上测试jQuery中是否成功绑定了这个属性

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

由于我们的插件只是针对 form 表单中的 input 进行校验,并不会对所有的 input 的值进行校验,所以我们接下来需要做一个限制:

(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的一个属性上:

(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 事件来进行触发,这个时候该怎么做?

==================================解疑======================================== 这个 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{} 的代码好上千百倍,可维护性,可扩展性都比较好,当然这种代码也不是一朝一夕就能写出来的,需要日积月累。

最后,大家一起加油吧。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

设计模式解析

设计模式解析

Alan Shalloway、James R.Trott / 徐言声 / 人民邮电出版社 / 2013-1 / 55.00元

《设计模式解析(第2版·修订版)》,本书首先概述了模式的基础知识,以及面向对象分析和设计在当代软件开发中的重要性,随后使用易懂的示例代码阐明了12个最常用的模式,使读者能够理解模式背后的基本原则和动机,理解为什么它们会这样运作。一起来看看 《设计模式解析》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试