JS组件化验证检测

作者:Jiang, Jilin

在web开发过程中,我们时常会遇到输入检测的情况。如果只是简单的输入验证检测,例如邮箱、电话等。我们可以简单的使用if…else if…来依次判断。但是如果这些判断存在延迟检测(例如ajax验证),再使用if…else if…已经无法满足需求了。

但是好在,利用jQuery的deffer方法。通过done(func)嵌套,可以实现序列化的检测:


$deferred.done(function() {

// Condition

$deferred.done(function() {

// Condition

$deferred.done(function() {

// Condition

$deferred.done(function() {

// Condition

$deferred.done(function() {

// Condition

// do something

});

});

});

});

});

通过嵌套依次进行检测

通常而言,通过这种嵌套,可以实现大多数的检测判断。但是如果我们考虑如下的检测顺序:

在这种多分支的情况下,使用deffer如下:


var _once = true;

function finalCheck() {

if(!_once) return;

_once = false;

$deferred.done(function() {

// Condition

// do something

});

}

$deferred.done(function() {

// Condition

$deferred.done(function() {

// Condition

$deferred.done(function() {

// Condition

finalCheck();

});

$deferred.done(function() {

// Condition

$deferred.done(function() {

// Condition

finalCheck();

});

});

});

});

可以发现随着分支增多,代码结构会变得越来越复杂。随着时间推移,如果需求变更。需要在判断中增加、删除甚至添加一个分支的时候。你会发现,这种结构很难维护。

那么如何通过封装来将此结构保持最好的维护性呢?我们可以通过将一个个检测条件打包,变成一个个组件。通过组合组件顺序,便可组织出我们需要的检测结构。


第一种结构设计:

new Condition(function(result) {

// Condition

result.success();

}).next(function(result) {

// Condition

result.success();

}).next(function(result) {

// Condition

result.success();

}).next(function(result) {

// Condition

result.success();

}).next(function(result) {

// Condition

result.success();

}). success(function() {

// do something

}).start();


第二种结构设计:

var seq1 = new Condition(function(result) {

// Condition

result.success();

}).next(function(result) {

// Condition

result.success();

});

var seq2_1 = new Condition(function(result) {

// Condition

result.success();

});

var seq2_2 = new Condition(function(result) {

// Condition

result.success()

}).next(function(result) {

// Condition

result.success();

});

seq1

.nextOr(seq2_1, seq2_2)

.next(function(result) {

// Condition

result.success();

}). success(function() {

// do something

}).start();

接下来,我们开始构建我们的组件容器:


var Condition = function(func) {

this.func = func;

this.root = null;

this.successFunc = null;

return this;

};

其中,通过调用next方法,可以添加一个新的检测条件,并返回一个新的组件:


Condition.prototype.next = function(func) {

var _next = new Condition(func);

_next.root = this.root || this;

this._next = _next;

return _next;

};

添加success方法用于存储检测成功的回调函数:


Condition.prototype.success = function(func) {

this.successFunc = func;

return this;

};

接着,就是添加start事件。当其被调用时,开始整个检测序列:


Condition.prototype._doAction = function() {

var _this = this;

_this.func({

success: function() {

// 如果该组件有success回调,则调用

if(_this.successFunc) {

_this.successFunc();

}

// 如果有后续组件则继续调用

if(_this._next) {

_this._next._doAction();

}

}

});

};

Condition.prototype.start = function() {

(this.root || this)._doAction();

};

测试如下:


new Condition(function(result) {

console.log("Condition 1");

result.success();

}).success(function() {

console.log("Success 1");

}).next(function(result) {

console.log("Condition 2");

result.success();

}).success(function() {

console.log("Success 2");

}).start();

// Condition 1

// Success 1

// Condition 2

// Success 2

有时候,我们会需要支持多个success事件,所以可以对success方法进行扩充:


var Condition = function(func) {

this.func = func;

this.root = null;

this.successFunc = [];

return this;

};


Condition.prototype.success = function(func) {

this.successFunc.push(func);

return this;

};


// 如果该组件有success回调,则调用

for(var i = 0 ; i < _this.successFunc.length ; i += 1) {

         _this.successFunc[i]();

}

然后考虑or分支结构,我们使用一个数组保存Condition列表。当执行到包含列表的组件时,遍历执行:


Condition.prototype.nextOr = function() {

var _next = new Condition(function(result) {

result.success();

});

_next.root = this.root || this;

this._next = _next;

this._nextList = arguments;

for(var i = 0 ; i < arguments.length ; i += 1) {

arguments[i].success(function() {

_next._doAction();

});

}

return _next;

};

同时,我们需要改写_doAction方法,使其支持多个Condition运行:


Condition.prototype._doAction = function() {

var _this = this;

_this.func({

success: function() {

// 如果该组件有success回调,则调用

if(_this.successFunc) {

_this.successFunc();

}

// 如果有后续组件则继续调用

if(_this._next) {

if(_this._nextList) {

for(var i = 0 ; i < _this._nextList.length ; i += 1) {

                                                        _this._nextList[i].start ();

                                               }

} else {

_this._next._doAction();

}

}

}

});

};

测试如下:


var s1 = new Condition(function(result) {

console.log("Condition 1.1");

result.success();

}).next(function(result) {

console.log("Condition 1.2");

result.success();

});

var s2_1 = new Condition(function(result) {

console.log("Condition 2-1");

result.success();

});

var s2_2 = new Condition(function(result) {

console.log("Condition 2-2.1");

result.success();

}).next(function(result) {

console.log("Condition 2-2.2");

result.success();

});

s1.nextOr(s2_1, s2_2).success(function() {

console.log("Condition 3");

}).start();

// Condition 1.1

// Condition 1.2

// Condition 2-1

// Condition 3

// Condition 2-2.1

// Condition 2-2.2

// Condition 3

我们发现通过两个分支走后,都调用了Condition3,这是我们不希望看到的。我们接下去要实现组件的once:


Condition.prototype.nextOr = function() {

var _once = true;

var _next = new Condition(function(result) {

result.success();

});

_next.root = this.root || this;

this._next = _next;

this._nextList = arguments;

for(var i = 0 ; i < arguments.length ; i += 1) {

arguments[i].success(function() {

if(!_once) return;

                            _once = false;

_next._doAction();

});

}

return _next;

};

测试如下:


// Condition 1.1

// Condition 1.2

// Condition 2-1

// Condition 3

// Condition 2-2.1

// Condition 2-2.2


小贴士:在Condition中使用once和原来的结构中使用once区别是什么?

将分支管理逻辑从代码中剥离可以减少代码复杂度,从而提升代码的可读性和维护性。

大致功能已经完成,但是仍然不满意。因为第一个分支已经成功的情况下,第二个分支还是走了一边。在不产生效果的情况下,该分支其实可以跳过。对doAction进行扩展:


Condition.prototype._doAction = function() {

var _succeed = false;

var _this = this;

var i;

_this.func({

success: function() {

// 如果该组件有success回调,则调用

for(i = 0 ; i < _this.successFunc.length ; i += 1) {

_this.successFunc[i]();

}

// 如果有后续组件则继续调用

if(_this._next) {

if(_this._nextList) {

for(i = 0 ; i < _this._nextList.length ; i += 1) {

if(_succeed) break;

_this._nextList[i].success(function() {

_succeed = true;

}).start();

}

} else {

_this._next._doAction();

}

}

}

});

};

测试如下:


// Condition 1.1

// Condition 1.2

// Condition 2-1

// Condition 3

还没有结束,如果分支中存在延迟操作,例如ajax请求等。仍然会走遍所有分支:


var s1 = new Condition(function(result) {

console.log("Condition 1.1");

result.success();

}).next(function(result) {

console.log("Condition 1.2");

result.success();

});

var s2_1 = new Condition(function(result) {

console.log("Condition 2-1");

setTimeout(function() {

result.success();

}, 100);

});

var s2_2 = new Condition(function(result) {

console.log("Condition 2-2.1");

setTimeout(function() {

result.success();

}, 100);

}).next(function(result) {

console.log("Condition 2-2.2");

setTimeout(function() {

result.success();

}, 100);

});

s1.nextOr(s2_1, s2_2).success(function() {

console.log("Condition 3");

}).start();

// Condition 1.1

// Condition 1.2

// Condition 2-1

// Condition 2-2.1

// Condition 3

// Condition 2-2.2

给每个分支添加一个标示符,当标示符为false时,停止该分支还未运行的所有检测:


var Condition = function(func) {

this.func = func;

this.root = null;

this.successFunc = [];

this._stop = false;

return this;

};


Condition.prototype._doAction = function() {

var _succeed = false;

var _this = this;

var i;

if((this.root || this)._stop) return;

};


Condition.prototype.start = function() {

(this.root || this)._stop = false;

(this.root || this)._doAction();

};


Condition.prototype.nextOr = function() {

var _once = true;

var _this = this;

var i;

var _next = new Condition(function(result) {

result.success();

});

_next.root = _this.root || _this;

_this._next = _next;

_this._nextList = arguments;

function doSuccess() {

for(i = 0 ; i < _this._nextList.length ; i += 1) {

                            var _root = _this._nextList[i];

                            _root = _root.root || _root;

                            _root._stop = true;

                   }

if(!_once) return;

_once = false;

_next._doAction();

}

for(i = 0 ; i < arguments.length ; i += 1) {

arguments[i].success(function() {

doSuccess();

});

}

return _next;

};

测试如下:


// Condition 1.1

// Condition 1.2

// Condition 2-1

// Condition 2-2.1

// Condition 3

好了,一个简易版的组件就完成了,通过这种组件化方式可以可方便的在中间插入、删除一个新的条件检测,也可以很容易创建一个分支检测。此处仅作抛砖引玉,考虑更复杂的情况,还有fail、always等事件处理。就让各位自己尝试着完成吧。

这里是github的参考代码地址:https://github.com/zombieJ/sequence(代码实现与文中略有出入)

时间: 2024-10-30 09:19:20

JS组件化验证检测的相关文章

JS 组件化开发 系列(一)

JS 组件化开发 系列 作为前端开发,组件化开发是你成长的必经之路.时间的积累逐渐摸索出自己比较好的开发方式. --- zenking (1)实现最简单的组件化: var jdb ={ alert: function(str) { alert(str); }, console:function (str) { console.log(str) } } 这样就是简单的实现 jdb.alert.jdb.console 两个方法. 但是呢? 现在需求改了, 需要实现链式调用. 就是像jquery 一样

vue.js组件化开发实践

前言 公司以往制作一个H5活动,特别是有一定统一结构的活动都要每次用html.css.js滚一次重复的轮子,费时费力.后来接到了一个基于模板的活动发布系统的需求,于是就有了下面的内容. 开始 需求一到,接就是怎么实现,技术选型自然成为了第一个问题.鉴于目前web前端mvvm框架的流行,以及组件化开发方式的出现,决定采用vue进行开发. 这里首先简单说下web前端组件化开发方式的历程: 最早的组件化结构,或者叫做组件化1.0时代,代码结构可能如下: 1 - lib/components/calen

js 组件化

我的github样例:https://github.com/hzijone/javascript_module js 用对象的方式实现组件化. 1.对一个对象里增加方法的方式: 把模块的变量传给函数,实现动态创建. 2.require.js加载多个js文件时,可以通过优化合并只成为一个js文件,避免网络拥塞.

组件化开发--搭建

前段工程化:      在前段开发的过程中,一些重复的工作由程序自动完成.在项目开发的过程中,css使用预处理器,js使用es6或者typescript或者coffeescript来开发      html使用模板语言开发,都需要进行编译,在项目开发的时候,按照模块化的思路进行拆分,但在上线的时候,为了提高运行的效率/性能,减少http请求,      需要对这些模块进行拼接,压缩等操作,测试.这些工作需要由工程化工具来完成,比如gulp的插件前段组件化:      css组件化开发     

Vue.js的组件化思想--上

Vue.js的组件化思想--上 一.Vue中的组件 Vue视图层的灵魂 -  组件化 组件(Component)是 Vue.js 最强大的功能之一: 组件可以扩展 HTML 元素,封装可重用的代码: 在较高层面上,组件是自定义元素, Vue.js 的编译器为它添加特殊功能.在有些情况下,组件也可以是原生 HTML 元素的形式,以 is 特性扩展. 二.全局组件的创建和注册  全局组件-步骤:1.创建组件Vue.extend(),指定组件的名称--2.注册组件Vue.component()--3.

闲话js前端框架(4)——组件化?有没有后端的事?

闲话js前端框架 前端人员=美工+设计+代码+测试 --题记 专题文章: 一.从avalonjs的模板说起 二.庞大的angularjs 三.再也不想碰DOM 四.组件化?有没有后端的事? 五.再看自己一年前设计的微型渲染引擎 六.在浏览器标准上做文章 七.抛开浏览器,构建应用容器 八.为何Flash.银光和Java都在网页端一蹶不振 本文属 西风逍遥游 原创, 转载请注明出处: 西风世界 http://blog.csdn.net/xfxyy_sxfancy 四.组件化?有没有后端的事? 提到组

JS组件系列——Form表单验证神器: BootstrapValidator

前言:做Web开发的我们,表单验证是再常见不过的需求了.友好的错误提示能增加用户体验.博主搜索bootstrap表单验证,搜到的结果大部分都是文中的主题:bootstrapvalidator.今天就来看看它如何使用吧. 一.源码及API地址 介绍它之前,还是给出它的源码以及API的地址吧. bootstrapvalidator源码:https://github.com/nghuuphuoc/bootstrapvalidator boostrapvalidator api:http://bv.do

Vue.js的组件化思想--下

Vue.js的组件化思想--下 一.组件间的通信        组件实例的作用域是孤立的:这意味着不能并且不应该在子组件的模板内直接引用父组件的数据.但是父子组件之间需要通信:父组件要给子组件传递数据,子组件需要将它内部发生的事情告知给父组件.          在 Vue.js 中,父子组件的关系可以总结为 props down, events up .父组件通过 props 向下传递数据给子组件,子组件通过 events 给父组件发送消息.如下图所示: 二. Prop - 父组件传递数据给子

原生js拼图,封装,组件化

利用原生js实现拼图游戏,实现封装,变为插件,组件化,传入参数调用, 使用立即执行函数,将变量私有化,不污染全局, 利用canvas展示效果,减少dom操作,不影响HTML结构: 1 var myPingTu = (function(){ 2 function init(row_i,dom){ 3 var myCanvas = dom; 4 var row = row_i || 3,// 行列数 5 arr = [], 6 num = row * row;// 块个数 7 if (!myCanv