纯javascript验证,100行超精简代码。
这篇文章转自--寒飞,原帖地址http://blog.csdn.net/luoyehanfei/article/details/42262249 QQ交流群235032949
纯javascript验证库详解
还是坚持一贯的原则,编写任何一个插件的时候不引用其它框架。这样做的好处与坏处、
好处:耦合度降低,提升自我编码水平,总有一天你就能成为编写框架的大神。
坏处:琐碎,耗时一点。
javascript的验证网上铺天盖地很多,jquery.validate.js也是非常强大的。为什么还要重复造轮子呢?
1、我喜欢所有的js插件都是在自己可控范围内,特别是高频率用到的插件。
2、纯js,减少库的依赖,我这里的验证库就100来行。
假设我有某个页面,就是验证是下帐号是否非法.......非得让我去引用上万行的jquery。。。。这尼玛不科学啊! 所以我重复造了这个轮子。
我喜欢先把最终的效果预设好,然后再朝着这个目标走下去。
先看html代码与调用代码,之后我们再慢慢分析实现代码
<div id="loginbox">
<div id="errdiv"></div>
<input type="text" id="username" data-validate-option="isAccount" />
<input type="text" id="username" data-validate-option="isNull"
data-validate-message="密码不能为空" /> <button onclick="save()">提交</button>
</div>
<script type="text/javascript">
function save() {
// if ($validate({ doc: "valibox", uiback: function (domone, valione, message) {
// document.getElementById("errdiv").innerHTML = message;
// }}).begin())
// {
// //自定义显示方式
// } if ($validate({ doc: "valibox" }).begin()) {
//默认显示方式
}
}
</script>
html代码中,有2个文本框,1个按钮,按钮是用来触发验证的(当然后面及时验证肯定是少不了的)
分析文本框,它有2个自定义的属性 data-validate-option(定义了验证的类型) data-validate-message(定义了验证不通过时提示的消息)
分析js代码,被注释掉的代码是自定义验证的uiback(默认验证的提示提供了一种悬浮的提示框,效果不错),假设你要自定义验证提示消息的显示方式,那么就用第一种,而觉得默认的已经够炫的话,你也可以保持默认的,反正就是尽量的灵活。
在它的构造函数残里,有个doc的属性,它是我们验证的关键,指定了需要验证的控件或“区域”,如果此项为空,那么将验证整个html,即包含在页面上所有需要验证的元素。
好了,参数非常的简单,简单的不能再简单了。下面直接上效果图:
OK。效果图已经出来了,多的不说,说说上面的input其中帐号是没有data-validate-message属性的,这个是由默认配置提供的(用户如果不提供,则使用默认消息->用户指编码人员),多的就不说了,这个是默认的效果提示。
下面重点来讲讲代码的实现部分:$validate({ doc: "valibox" }).begin()) ,这个是我们代码的最终调用形态,首先构造validate对象,传入构造参数,然后调用begin(),即开始验证进行验证,验证成功返回true,失败返回false.
OK,贴源码。
(function () {
$validate = window.$validate = function (options) {
return new $validate.prototype.init(options);
};
$validate.prototype = {
valilist: [
{ name: "isEmail", expression: /^\w+([\.\-]\w+)*\@\w+([\.\-]\w+)*\.\w+$/, message: "邮箱格式不正确" },
{ name: "isInt", expression: /^[-+]?\d*$/, message: "必须为整数" },
{ name: "isDate", expression: /^(\d{4})\-(\d{2})\-(\d{2})$/, message: "日期格式不正确" },
{ name: "isDateShort", expression: /^(\d{4})\-(\d{2})\-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/, message: "日期格式不正确" },
{ name: "isLetter", expression: /^[a-zA-Z]+$/, message: "必须为英文字母" },
{ name: "isTel", expression: /((d{3,4})|d{3,4}-)?d{7,8}(-d{3})*/, message: "电话格式不正确" },
{ name: "isAccount", expression: /^[a-zA-Z][a-zA-Z0-9_]{5,19}$/, message: "必须以字母开头,且是数字、字母、下划线的6-20位组合" },
{ name: "isUrl", expression: /a-zA-z]+:\/\/[^\s]*/, message: "网址格式不正确" },
{ name: "isIdcard", expression: /d{18}|d{15}/, message: "身份证号必须为15或18位数字" },
{ name: "isTel", expression: /d{6}/, message: "邮政编码必须为6位数字" },
{ name: "isNull", expression: /\S/, message: "此项不能为空" }
],
extend: function EvUpdate(NewObject, OldObject) {
function clonePrototype() { }
clonePrototype.prototype = NewObject;
var obj = new clonePrototype();
for (var ele in obj) {
if (typeof (obj[ele]) == "object")
EvUpdate(obj[ele], OldObject[ele]);
else
OldObject[ele] = obj[ele];
}
},
config: { doc: null, realtime: false, callback: null, uiback: null, tags: "input", valiattr: "data-validate-option", valimessageattr: "data-validate-message" },
init: function (options) {
this.extend(options, this.config);
if (typeof (this.config.doc) == "string") {
this.config.doc = document.getElementById(this.config.doc);
}
return this;
},
serch: function (name) {
for (var i = 0; i < this.valilist.length; i++) {
if (name == this.valilist[i].name) {
return this.valilist[i];
}
}
return null;
},
begin: function () {
if (!this.config.doc) {
return false;
}
if (this.config.doc.hasChildNodes()) {
var alls = new Array();
alls.push(this.config.doc.getElementsByTagName(this.config.tags));
for (var i = 0; i < alls.length; i++) {
for (var y = 0; y < alls[i].length; y++) {
var valitype = alls[i][y].getAttribute(this.config.valiattr);
var valione = this.serch(valitype);
if (valitype && valione) {
var value = alls[i][y].value;
var message = alls[i][y].getAttribute(this.config.valimessageattr);
var result = value.match(valione.expression);
if (result == null) {
this.show(alls[i][y], valione, message);
return false;
}
}
}
}
}
else {
var valitype = this.config.doc.getAttribute(this.config.valiattr);
var valione = this.serch(valitype);
if (valitype && valione) {
var value = this.config.doc.value;
var message = this.config.doc.getAttribute(this.config.valimessageattr);
var result = value.match(valione.expression);
if (result == null) {
this.show(this.config.doc, valione, message);
return false;
}
}
}
return true;
},
show: function (domone, valione, message) {
if (this.config.uiback == null) {
domone.focus();
var valimessage = message != null ? message : valione.message;
var _hg = domone.clientHeight;
var _width = domone.clientWidth;
var t = domone.offsetTop;
var l = domone.offsetLeft;
while (domone = domone.offsetParent) {
t += domone.offsetTop;
l += domone.offsetLeft;
};
t = t + _hg;
function parseNode(arg) { var objE = document.createElement("div"); objE.innerHTML = arg; return objE.childNodes[0]; };
var str = "<div id=\"_lxpfloattip_\" onclick=\"javascript:document.body.removeChild(document.getElementById('_lxpfloattip_'))\" style=\"width:" + _width + "px;z-index: 800000; position: absolute; left: " + l + "px; top: " + t + "px;\"><table cellspacing=\"0\" cellpadding=\"0\" border=\"0\" style=\"width:200px\"><tbody><tr style=\"height:auto\"><td class=\"tip_lefttop\"></td><td class=\"tip_top\"></td><td class=\"tip_righttop\"></td></tr><tr><td class=\"tip_left\"></td><td id=\"_lxpfloattip_value\" bgcolor=\"#ffffda\" style=\"color:navy;font-size:14px\">" + valimessage + "</td><td class=\"tip_right\"></td></tr><tr><td class=\"tip_leftbottom\"></td><td class=\"tip_bottom\"></td><td class=\"tip_rightbottom\"></td></tr></tbody></table></div>";
var validatedemo = parseNode(str);
document.body.appendChild(validatedemo);
setTimeout("document.body.removeChild(document.getElementById(\"_lxpfloattip_\"))", 2000);
}
else {
domone.focus();
this.config.uiback(domone, valione, message);
}
}
};
$validate.prototype.init.prototype = $validate.prototype;
})();
1、第一段代码:$validate = window.$validate = function (options) { return new $validate.prototype.init(options); };
我们调用时使用的 $validate(....);从这里可以看出来$validate=某个函数->返回了一个对象,实际上当我们使用$validate(...)时,就调用了function (options) { return new $validate.prototype.init(options); };这个函数,返回了一个新的实例。
2、构造函数:它返回了一个new $validate.prototype.init(options); ,这句话如果读过jquery源码的朋友们很容易理解。单从这里我们理解不了它具体返回了什么东西,得扒开init函数看一下。
init: function (options) {
this.extend(options, this.config);
if (typeof (this.config.doc) == "string") {
this.config.doc = document.getElementById(this.config.doc);
}
return this;
},
init的函数接受一个options的参数,这个参数实际上就是从$validate(....)构造函数中过来的。重点来了,
this.extend,this.config,return this; 这里连续用到了几个this,这是怎么回事呢?精通js的朋友知道this的作用域的问题,这里的作用域是在init函数里,this的话不应该指向$validate.prototype啊(this.extent是在$validate.prototype扩展里的),那它到底是怎么可以这样直接调用$validate.prototype域的成员的呢?这里涉及到一个prototype实现继承的方法,这里的这个方法和jquery的选择器实现是如出一辙。我们来看看整个代码的最后一行:$validate.prototype.init.prototype = $validate.prototype; 最后一行这样写 init.prototype=$validate.prototype。原来如此,init的原型引用到$validate的原型上去了,怪不得在init函数中的this可以调用 this.extend,this.config,return this; 这些玩意。
原型引用就讲解到这里,实际上init里的this 就是$validate的原型引用。
接着看
init this.extend(options, this.config);
if (typeof (this.config.doc) == "string") {
this.config.doc = document.getElementById(this.config.doc);
}
这2句代码,第一句是深层赋值(这是一个我在项目中经常会用到的方法,它的作用是可以深度赋值),
我打个简单的比方,假设我们有个函数:
function fuc(options)
{
var thisoptions ={name:"张三",age:23,range:{left:10,right:20}};
//这里我需要根据传递进来的参数options对 thisoptions进行赋值,
thisoptions=options;//这样是错误的,为什么?请看下面调用
}
假设我调用时传递:fuc({name:"李四",age:20,range:{left:20}};) //
当进行调用之后,在fuc内部,如果使用thisoptions.range.right 会报错,因为传递的参数并没有right的参数,所以在函数内部用=的方式,会把内部的成员结构破坏掉。解决它有2种办法,一个就是对象属性少量的情况下,单独赋值,这样可能会非常麻烦(老办法,不可取),第二种就是我上面用到的深层赋值了,它不会破坏函数内部成员的结构,使用方便,以后添加了属性也不用更改代码。这个解释就说道这,有兴趣的自己去试试。
接着上面的代码说 if (typeof (this.config.doc) == "string") 没啥说的了,这里就已经说明了,在传递$validate()参数即可为字符串,也可以为对象。字符串会根据id去匹配,对象就直接是对象了。
3、valilist。这是一个数组,里面定义了所有常用的验证,这里我只写了几个,用的时候自己加进去就行。非常简单,网上把正则百度出来粘贴进去就OK。
4、config: { doc: null, realtime: false, callback: null, uiback: null, tags: "input", valiattr: "data-validate-option", valimessageattr: "data-validate-message" },
定义了验证的配置,doc刚才已经说了,realtime是否及时验证,默认false,(及时验证即焦点离开文本框时就会触发验证,这个我还没去实现,实现也非常简单)。callback:原先设计用来处理验证失败的回调函数(现在暂时没用),uiback列子中已用代码说明,自定义显示UI.tags:默认验证的标签,input,可以加其它的,比如select,lable,div等,都可以进行验证,不仅仅是表单哟,呵呵。 valiattr和valimessageattr,这个就是更为强大的配置,可以和你现有的验证进行整合。属性名可以为其它,并非规定的data-validate-option和data-validate-message。
5、serch,找寻与匹配option对象数组中的验证规则,不太想说,太简单了自己看。
6、begin,这里也基本没啥复杂的东西了,上面解释的够清楚了,主要就是根据配置规则进行验证了。看一遍就懂
7、show,显示错误信息,非常简单,自己看看吧。
纯javascript验证,100行超精简代码。的更多相关文章
- 转: 通过不到100行Go代码打造你自己的容器
备注:这个文章讲容器,讲的比较的浅显易懂.推荐,前期入行者看. 转: http://www.infoq.com/cn/articles/build-a-container-golang?utm_sou ...
- 100行代码实现HarmonyOS“画图”应用,eTS开发走起!
本期我们给大家带来的是"画图"应用开发者Rick的分享,希望能给你的HarmonyOS开发之旅带来启发~ 介绍 2021年的华为开发者大会(HDC2021)上,HarmonyOS ...
- 100 行代码实现的 JavaScript MVC 样式框架
介绍 使用过 JavaScript框架(如 AngularJS, Backbone 或者Ember)的人都很熟悉在UI(用户界面,前端)中mvc的工作机理.这些框架实现了MVC,使得在一个单页面中实现 ...
- 100行代码让您学会JavaScript原生的Proxy设计模式
面向对象设计里的设计模式之Proxy(代理)模式,相信很多朋友已经很熟悉了.比如我之前写过代理模式在Java中实现的两篇文章: Java代理设计模式(Proxy)的四种具体实现:静态代理和动态代理 J ...
- 原生态纯JavaScript 100大技巧大收集---你值得拥有
1.原生JavaScript实现字符串长度截取 function cutstr(str, len) { var temp; var icount = 0; var patrn = /[^\x00-\x ...
- 100行代码实现现代版Router
原文:http://www.html-js.com/article/JavaScript-version-100-lines-of-code-to-achieve-a-modern-version ...
- 仅100行的JavaScript DOM操作类库
如果你构建过Web引用程序,你可能处理过很多DOM操作.访问和操作DOM元素几乎是每一个Web应用程序的通用需求.我们我们经常从不同的控件收集信息,我们需要设置value值,修改div或span标签的 ...
- GuiLite 1.2 发布(希望通过这100+行代码来揭示:GuiLite的初始化,界面元素Layout,及消息映射的过程)
经过开发群的长期验证,我们发现:即使代码只有5千多行,也不意味着能够轻松弄懂代码意图.痛定思痛,我们发现:虽然每个函数都很简单(平均长度约为30行),可以逐个击破:但各个函数之间如何协作,却很难说明清 ...
- 纯javascript代码编写计算器程序
今天来分享一下用纯javascript代码编写的一个计算器程序,很多行业都能用到这个程序,例如做装修预算.贷款利率等等. 首先来看一下完成后的效果: 具体代码如下:(关注我的博客,及时获取最新WEB前 ...
随机推荐
- vim 粘贴复制操作
原文链接:http://www.cnblogs.com/lansh/archive/2010/08/19/1803378.html vi编辑器有3种模式:命令模式.输入模式.末行模式.掌握这三种模式十 ...
- javascript设计模式之中介者模式
/* * 小游戏演示中介者模式 * Home 按键 1 * Guest 按键 0 * 半分钟内看谁按下的次数多 * * 参与的对象: * 玩家 * 计分板 * 中介者 * * 中介者模式使对象之间松耦 ...
- cocos2d-x 学习资料汇总
cocos2d-x配置问题 - 我要飞的更高 - 博客频道 - CSDN.NET Cocos2d-x win7 + vs2010 配置图文详解(亲测) - 子龙山人 - 博客园 WINDONWS7+V ...
- LeetCode Add Binary 两个二进制数相加
class Solution { public: string addBinary(string a, string b) { if(a==""&&b==" ...
- Aizu 0525 Osenbei(状压+贪心)
题意:翻煎饼,只能横着翻或者竖着翻.问最多有多少朝上? 行只有10,所以枚举一下2^10的状态,每列取0或1中最大的一个. 在枚举外面把饼翻好,枚举里面指针指一下就好.(位运算或bitset乱搞 #i ...
- hdu-1556 Color the ball---树状数组+区间修改单点查询
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1556 题目大意: Problem Description N个气球排成一排,从左到右依次编号为1,2 ...
- slice 与 substring
Array数组:slice() slice() : 截取 Array 的部分元素,然后返回一个新的Array. var arr = ['a', ' b', 'c', 'd', 'e', 'f', 'g ...
- py2exe --- show error: MSVCP90.dll + matplotlib issues
问题1: show error: MSVCP90.dll: No such file or directory 创建生成exe文件的脚本添加: import py2exe from distutils ...
- 2018.6.2 AndroidStudio项目中的问题:===== oast.LENGTH_LONG和Toast.LENGTH_SHORT分别对应多长时间
oast.LENGTH_LONG和Toast.LENGTH_SHORT分别对应多长时间 在Android源码中的NotificationManagerService.java这个类中定义了两个静态变量 ...
- python_75_json与pickle序列化2
import pickle def say(name):print('Hi!',name)#用完会释放,要想反序列化,要重新写上该函数 info={ 'name':'Xue Jingjie', 'ag ...