数据校验插件开发

本文涉及的产品
可视分析地图(DataV-Atlas),3 个项目,100M 存储空间
简介: 在看完了《JavaScript插件编写指南》之后,最激动人心的时刻到了!我们着手开始做一个数据校验插件吧!首先,我们先初始化一个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{}的代码好上千百倍,可维护性,可扩展性都比较好,当然这种代码也不是一朝一夕就能写出来的,需要日积月累,我依旧觉得自己很菜,所以我每天都在学习。

最后,大家一起加油吧。

相关实践学习
DataV Board用户界面概览
本实验带领用户熟悉DataV Board这款可视化产品的用户界面
阿里云实时数仓实战 - 项目介绍及架构设计
课程简介 1)学习搭建一个数据仓库的过程,理解数据在整个数仓架构的从采集、存储、计算、输出、展示的整个业务流程。 2)整个数仓体系完全搭建在阿里云架构上,理解并学会运用各个服务组件,了解各个组件之间如何配合联动。 3&nbsp;)前置知识要求 &nbsp; 课程大纲 第一章&nbsp;了解数据仓库概念 初步了解数据仓库是干什么的 第二章&nbsp;按照企业开发的标准去搭建一个数据仓库 数据仓库的需求是什么 架构 怎么选型怎么购买服务器 第三章&nbsp;数据生成模块 用户形成数据的一个准备 按照企业的标准,准备了十一张用户行为表 方便使用 第四章&nbsp;采集模块的搭建 购买阿里云服务器 安装 JDK 安装 Flume 第五章&nbsp;用户行为数据仓库 严格按照企业的标准开发 第六章&nbsp;搭建业务数仓理论基础和对表的分类同步 第七章&nbsp;业务数仓的搭建&nbsp; 业务行为数仓效果图&nbsp;&nbsp;
目录
相关文章
|
1月前
|
JavaScript 测试技术 开发者
确定 Babel 插件的功能是否符合项目需求
【10月更文挑战第25天】细致的评估方法,可以较为准确地确定 Babel 插件的功能是否真正符合项目需求,从而为项目选择合适的插件,保障项目的顺利开发和高质量交付。
|
4月前
|
前端开发 JavaScript Java
如何使用JSR 303 进行后台数据校验?
这篇文章详细介绍了如何使用JSR 303进行后端数据校验,包括JSR 303的基本概念、使用原因、常见操作,以及如何通过注解进行数据校验、分组校验和自定义校验注解的方法和实际应用示例。
如何使用JSR 303 进行后台数据校验?
|
7月前
|
JSON 资源调度 前端开发
前端工具 Prettier 详细使用流程(兼容ESLint)
前端工具 Prettier 详细使用流程(兼容ESLint)
256 0
|
7月前
|
JSON 移动开发 资源调度
前端工具 Prettier 详细使用流程(兼容ESLint)
前端工具 Prettier 详细使用流程(兼容ESLint)
465 0
|
4月前
|
存储 SQL 测试技术
单元测试问题之JCode5插件在项目中的实际应用效果如何解决
单元测试问题之JCode5插件在项目中的实际应用效果如何解决
111 3
|
7月前
|
开发者
Eslint插件使用配置, 规范化开发, 详细配置流程
Eslint插件使用配置, 规范化开发, 详细配置流程
|
6月前
|
前端开发 Java 数据库
SpringMVC的架构有什么优势?——表单和数据校验(四)
SpringMVC的架构有什么优势?——表单和数据校验(四)
|
7月前
|
XML Java 数据库连接
代码生成插件easycode
代码生成插件easycode
|
前端开发 Java API
数据校验(前端数据校验、JSR303校验)
数据校验(前端数据校验、JSR303校验)
269 0
|
XML JSON JavaScript
技术必备:推荐一款接口自动化测试数据校验神器
技术必备:推荐一款接口自动化测试数据校验神器
618 0
技术必备:推荐一款接口自动化测试数据校验神器