JS自定义表单提交处理方案
- JS自定义数据提交处理方案
问题
在Ajax技术流行的今天,我遇到了一个很头疼的问题,我需要维护一个前人开发的问题单模块功能,并且不停的迭代开发,而这个问题就是问题单字段特别多,而且除了更新问题单外,问题单的提交审核的操作几乎要对每个字段进行校验,不满足校验时提示用户并取消提交操作。
要知道只C#的后台模型这么简单的属性写法加上注释的话也差不多四五百行代码了,何况要在前台获取表单数据,然后对获取的结果进行校验,检验通过后才能提交表单。这样的代码开发及维护起来工作量那是相当的大,而且极容易出错,举个例子,需要提交员工的数据如下:
<input type="hidden" id="id" value="1"> <input type="text" id="number"> <input type="text" id="Name"> <input type="text" id="Age"> <input type="text" id="BirthDay">
传统的处理方式
也是我接手这个模块时是这样获取并校验的:
function getCon(){
return{
Number: $('#number').val(),
Name: $('#name').val(),
Age: $('#age').val(),
BirthDay: $('#birthDay').val(),
}
}
function check(con){
if(!con.Number){
return '工号不能为空!';
}
if(!con.Name){
return '姓名不能为空!';
}
if(con.Age == null){
return '年龄不能为空!';
}
if(!/^\d{2}$/.test(con.Age)){
return '请输入两位数字';
}
if(con.BirthDay == null){
return 'BirthDay不能为空!';
}
if(con.BirthDay < '1988-02-01'){
return '年龄太大!';
}
}
var con = getCon();
var res = check(con);
if(res){
alert(res);
return;
}
$.post('action', con, function(data){
alert(data);
}, 'json')
这个例子字段很少,都可以看出来,代码量却不少,而且各个地方分散的太严重,又相互联系,新增一个属性会在页面改动很多添加代码,很容易漏,而且很难找到。因此,我便着手写自己的框架来处理这样的问题。
封装JS模型
我首先设计了一个JS模型用来存储,键为后台模型的属性,值包含前台属性绑定的ID,类型valueType以及校验的条件checkTip,这样的好处是,将页面也后台模型通过JS模型联系起来,当需求变化的时候只需要改变对应属性的模型就好,例子如下:
var model = {
id: 1,
number: {
id:"number",
valueType:function(id){return parseInt($(id).val())},
checkTip:"工号不能为空"
},
Name:{
id:"name",
valueType:"string",
checkTip:"姓名不能为空"
},
Age:{
id:"age",
valueType:'',
checkTip:function(id){
if (!/\d{2}/.test($(this).val())) return '请输入两位数字';
return '';
}
},
BirthDay:{
id:"birthday",
valueType:"date",
checkTip:function(val,id){
if(val < '1988-02-01') return '年龄太大!'
}
},
}
编写通用处理框架
然后我抽取了一个非常强大的方法,实现可顺便校验的查询或提交所需要的字段信息,使用此方法可减少大量的代码和降低字段太多时出错的概率,这个方法会根据valueType和id自动从页面获取对应的值,需要校验时还能自动根据checkTip进行校验,不校验或者校验无误时返回格式为{k:v},校验错误时返回格式为 {isError:true,errorMsg:'message',{k:v}},源码如下:
function conditionHandler (model,isCheck,callBack){
var newmodel = {};
//入口参数处理
if(typeof isCheck === 'function'){
callBack = isCheck;
isCheck = undefined;
}
if(isCheck === true){
//需要校验时,一边获取条件一边校验是否满足要求,不满足立即退出
newmodel.isError = false;
newmodel.errorMsg = '';
newmodel.model = {};
muphy.each(model, function(k,v){
var val = getVal(this);
//必须校验的字段checkTip不为空
if(!muphy.isNull(this.checkTip)){
if(typeof this.checkTip === 'function'){
//自定义校验
var res = this.checkTip.call(val,val,'#' + this.id);
if(!muphy.isNull(res)){
newmodel.isError = true;
newmodel.errorMsg = res;
newmodel.model[k] = val;
return false;
}
} else {
//默认判空
if(muphy.isNull(val)){
newmodel.isError = true;
newmodel.errorMsg = this.checkTip;
newmodel.model[k] = val;
return false;
}
}
}
newmodel.model[k] = val;
});
if(!newmodel.isError){
newmodel = newmodel.model;
}
} else {
//不需要校验时,直接获取条件
muphy.each(model, function(k,v){
newmodel[k] = getVal(this);
})
}
//当传入了回调函数是,可以回调处理结果
if(typeof callBack === 'function'){
callBack.call(newmodel,newmodel);
}
//返回条件参数
return newmodel;
//获取单个条件值
function getVal(obj){
var val;
if(typeof obj === 'string' || typeof obj === 'number' || obj instanceof Date){
val = obj;
} else if(obj.valueType instanceof Array || obj.valueType === 'string'){
val = muphy.nvl($('#' + obj.id).val(), []).join(',');
} else if(typeof obj.valueType === 'function'){
val = obj.valueType.call('#' + obj.id, '#' + obj.id);
} else {
val = muphy.nvl($('#' + obj.id).val());
}
return val;
}
}
调用框架处理提交
最后是调用的过程,调用是非常简单的,获取条件的结果可以在回调函数中直接处理,也可以用变量来接收后在处理,功能灵活且强大,调用封装的处理函数:
conditionHandler(model, true, function(con){
if(con.isError){
alert(con.errorMsg);
return;
}
$.post('action', con, function(data){
alert(data);
}, 'json')
})
优点
从这里可以看出来,以后需要改动的时候,只需要改动JS模型对影的属性信息就好,其他地方几乎不变。
封装的源代码
/*!
* muphyjs JavaScript Library v1.0.0
* http://www.muphy.me/
*
* Includes jQuery.js
* http://jquery.com/
*
* Copyright 莫非(muphy)
*
* Date: 2018-07-16
*/
(function(window,$){
var muphy = Object.create({
/*@description 判断函数是否为空
*@method isNull
*@for muphy
*@examples muphy.isNull(data);
*@param {object} data 需要判断空的对象
*@return {bool} 如果为空则返回 true,否则返回 false
*/
isNull: function(data){
if(data === null || data === undefined){
return true;
}
if( typeof data === "String" && data.trim() ==='' ){
return true;
}
if(data instanceof Array && data.length == 0){
return true;
}
return false;
},
/*@description 将空对象转换为指定的值
*@method nvl
*@for muphy
*@examples
*1. muphy.nvl(data);//data为空时返回 ''
*2. muphy.nvl(data,[]);//data为空时返回 []
*@param {object} data 需要判断空的对象
*@param {object} obj 为空时返回的对象
*@return {object} 如果为空则返回 obj,否则返回 data
*/
nvl: function(data,obj){
if(obj === 0) return 0;
return data || obj || '';
},
/*@description 遍历处理数组、集合或者对象,同jQuery.each
*@method each
*@for muphy
*@examples
*1. muphy.each(arr, function(){console.log(this);});//遍历打印数组的值
*2. muphy.each(obj,function(k,v){console.log(k + ':' + v);});//遍历打印对象键值对
*@param {object} obj 需要遍历的数组、集合或者对象
*@param {function} fun 回调函数,处理每项结果
*/
each: function(obj,fun){
for (var key in obj) {
if(fun.call(obj[key], key, obj[key]) === false){
break;
}
}
},
/*@description 为元素添加事件处理函数
*@method addEvent
*@for muphy
*@param {Elenent} ele 需要绑定事件的元素
*@param {string} type 事件类型
*@param {function} handler 事件处理程序
*/
addEvent: function(ele,type,handler){
if(ele.addEventListener){
ele.addEventListener(type,handler,false);
} else if(ele.attachEvent){
ele.attachEvent("on" + type, handler);
} else {
ele["on" + type] = handler;
}
},
/*@description 移除元素事件处理函数
*@method removeEvent
*@for muphy
*@param {Elenent} ele 需要移除事件的元素
*@param {string} type 事件类型
*@param {function} handler 事件处理程序
*/
removeEvent: function(ele,type,handler){
if(ele.removeEventListener){
ele.removeEventListener(type,handler,false);
} else if(ele.detachEvent){
ele.detachEvent("on" + type, handler);
} else {
ele["on" + type] = null;
}
},
/*@description 为元素添加拖动事件
*@method _dragEvent
*@for muphy
*@param {Elenent} ele 需要拖动事件的元素,必须绝对定位,并且添加类名 class='draggable'
*/
_dragEvent: function(ele){
var drag = null,
diffx = 0,
diffy = 0,
$e = null;
if($.isNull(ele)) return;
if(!($e = $(ele))) return;
$(document).bind("mousedown",handleEvent);
$(document).bind("mousemove",handleEvent);
//$(document).bind("mouseup",handleEvent);
$.muphy.addEevent(document,"mouseup",handleEvent);
function handleEvent(event){
event = event || window.event;
var target = $e[0];
switch(event.type){
case "mousedown":
if($m.nvl(target.className).indexOf("draggable") > -1){
drag = target;
diffx = event.clientX - target.offsetLeft;
diffy = event.clientY - target.offsetTop;
}
break;
case "mousemove":
if(drag !== null){
drag.style.left = (event.clientX - diffx) + "px";
drag.style.top = (event.clientY - diffy) + "px";
}
break;
case "mouseup":
drag = null;
break;
}
}
},
/*@description 为元素添加拖动事件,并且新增自定义事件:dragstart、drag、dragend
*@method dragEvent
*@for muphy
*/
dragEvent: function(){
var drag = null,
ce = new muphy.costomEvent();
diffx = 0,
diffy = 0;
$(document).unbind("mousedown",handleEvent);
$(document).unbind("mousemove",handleEvent);
$(document).unbind("mouseup",handleEvent);
$(document).bind("mousedown",handleEvent);
$(document).bind("mousemove",handleEvent);
$(document).bind("mouseup",handleEvent);
function handleEvent(event){
event = event || window.event;
var target = event.target || event.srcElement;
switch(event.type){
case "mousedown":
if(muphy.nvl(target.className).indexOf("draggable") > -1){
drag = target;
diffx = event.clientX - target.offsetLeft;
diffy = event.clientY - target.offsetTop;
event.type = "dragstart";
ce.fire(event)
}
break;
case "mousemove":
if(drag !== null){
drag.style.left = (event.clientX - diffx) + "px";
drag.style.top = (event.clientY - diffy) + "px";
event.type = "drag";
ce.fire(event)
}
break;
case "mouseup":
if(drag != null){
drag = null;
event.type = "dragend";
ce.fire(event)
}
break;
}
}
return ce;
},
/*@description 自定义事件
*@method _costomEvent
*@for muphy
*/
_costomEvent: function(){
var handlers = {};
// 添加自定义事件的函数
this.addEvent = function(type, handler){
if(typeof handlers[type] === 'undefined'){
handlers[type] = [];
}
handlers[type].push(handler);
}
// 移除自定义事件的函数
this.removeEvent = function(type, handler){
if(handlers[type] instanceof Array){
muphy.each(handlers[type], function(i){
if(this === handler){
handlers[type].splice(i,1);
return false;
}
});
}
}
// 触发自定义事件
this.fire = function(event){
if(!event.target){
event.target = this;
}
if(handlers[event.type] instanceof Array){
muphy.each(handlers[event.type],function(){
this(event);
})
}
}
},
/*@description 自定义事件
*@method _costomEvent
*@for muphy
*/
costomEvent: function(){
},
/*@description 实现可顺便校验的查询或提交所需要的字段信息,使用此方法可减少大量的代码和降低字段太多时出错的概率
*@method conditionHandler
*@for muphy
*@param {object} model 自定义在页面和后台模型之间建立联系的model
*@examples
1.model:{
id: 1,
number: {id:"number", valueType:function(id){return parseInt($(id).val())}, checkTip:"工号不能为空"},
Name:{id:"name", valueType:"string", checkTip:"姓名不能为空"},
Age:{id:"age", valueType:'', checkTip:function(id){if (!/\d{2}/.test($(this).val())) return '请输入两位数字'; return '';}},
BirthDay:{id:"birthday", valueType:"date", checkTip:function(val,id){if(val < '1988-02-01') return '年龄太大!'}},
}
2.校验:muphy.conditionHandler(model, true, fun)
3.不校验:muphy.conditionHandler(model, fun);
*@param {bool} isCheck 是否需要校验,需要校验必须为true,不需要时可不传
*@param {_function} callBack 回调函数,获取完成传入后台的参数后可以直接在回调函数中处理
*@return {object} newmodel 返回获取的参数,校验无误是返回格式为{k:v},校验错误时返回格式为{isError:true,errorMsg:'message',{k:v}}
*/
conditionHandler: function(model,isCheck,callBack){
var newmodel = {};
//入口参数处理
if(typeof isCheck === 'function'){
callBack = isCheck;
isCheck = undefined;
}
if(isCheck === true){
//需要校验时,一边获取条件一边校验条件是否满足要求,不满足立即退出
newmodel.isError = false;
newmodel.errorMsg = '';
newmodel.model = {};
muphy.each(model, function(k,v){
var val = getVal(this);
//必须校验的字段checkTip不为空
if(!muphy.isNull(this.checkTip)){
if(typeof this.checkTip === 'function'){
//自定义校验
var res = this.checkTip.call(val,val,'#' + this.id);
if(!muphy.isNull(res)){
newmodel.isError = true;
newmodel.errorMsg = res;
newmodel.model[k] = val;
return false;
}
} else {
//默认判空
if(muphy.isNull(val)){
newmodel.isError = true;
newmodel.errorMsg = this.checkTip;
newmodel.model[k] = val;
return false;
}
}
}
newmodel.model[k] = val;
});
if(!newmodel.isError){
newmodel = newmodel.model;
}
} else {
//不需要校验时,直接获取条件
muphy.each(model, function(k,v){
newmodel[k] = getVal(this);
})
}
//当传入了回调函数是,可以回调处理结果
if(typeof callBack === 'function'){
callBack.call(newmodel,newmodel);
}
//返回条件参数
return newmodel;
//获取单个条件值
function getVal(obj){
var val;
if(typeof obj === 'string' || typeof obj === 'number' || obj instanceof Date){
val = obj;
} else if(obj.valueType instanceof Array || obj.valueType === 'string'){
val = muphy.nvl($('#' + obj.id).val(), []).join(',');
} else if(typeof obj.valueType === 'function'){
val = obj.valueType.call('#' + obj.id, '#' + obj.id);
} else {
val = muphy.nvl($('#' + obj.id).val());
}
return val;
}
}
});
/*@description 自定义事件添加原型函数
*@method costomEvent
*@static costomEvent的原型对象
*@for muphy
*/
(function(muphy){
muphy.costomEvent.prototype = {
constructor: muphy.costomEvent1,
handlers:{},
addEvent: function(type, handler){
if(typeof this.handlers[type] === 'undefined'){
this.handlers[type] = [];
}
this.handlers[type].push(handler);
},
removeEvent: function(type, handler){
if(this.handlers[type] instanceof Array){
var handlers = this.handlers[type];
muphy.each(handlers, function(i){
if(this === handler){
handlers.splice(i,1);
return false;
}
});
}
},
fire: function(event){
if(!event.target){
event.target = this;
}
if(this.handlers[event.type] instanceof Array){
muphy.each(this.handlers[event.type],function(){
this(event);
})
}
}
}
})(muphy);
window.$m = muphy;
})(window,jQuery);
JS自定义表单提交处理方案的更多相关文章
- DedeCMS实现自定义表单提交后发送指定QQ邮箱法
https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&tn=monline_3_dg&wd=dedecms 邮箱&oq=d ...
- DedeCMS实现自定义表单提交后发送指定QQ邮箱的方法
如月cruyue在做DedeCMS自定义表单发送邮箱的教程,发现大部分都是在php文件里写死固定字段内容,这样虽然也能实现自定义表单提交后发送指定邮箱,但是很不智能,如月cruyue想要一个我们自定义 ...
- phpcms v9自定义表单提交后返回上一页实现方法
PHPcms v9中提交自定义表单后默认都是回到首页的,是不是感觉很不爽! 接下来,就说下phpcms v9自定义表单提交后返回上一页实现方法. 1.找到这个文件 phpcms\modules\for ...
- dedecms自定义表单提交成功后提示信息修改和跳转链接修改
我们在用dedecms自定义表单提交成功后提示信息一般是"Dedecms 提示信息",这个要怎么改成自己想要的文字呢?还有就是提示页停留时间,目前估计就2秒,太快了,要如何设置长点 ...
- jquery.form.js 让表单提交更优雅
jquery.form.js 让表单提交更优雅.可以页面不刷新提交表单,比jQuery的ajax提交要功能强大. 1.引入 <script src="/src/jquery-1.9.1 ...
- [转]django自定义表单提交
原文网址:http://www.cnblogs.com/retop/p/4677148.html 注:本人使用的Django1.8.3版本进行测试 除了使用Django内置表单,有时往往我们需要自定义 ...
- Django初体验(一):自定义表单提交
注:本人使用的Django1.8.3版本进行测试 除了使用Django内置表单,有时往往我们需要自定义表单.对于自定义表单Post方式提交往往会带来由CSRF(跨站请求伪造)产生的错误"CS ...
- dedecms自定义表单提交获取时间跟ip地址
相信大家在用织梦做网站的时候都用过自定义表单做留言,但是如何查看客户什么时间填写的表单,和客户的IP地址呢? 我在网上找了很多JS文件,但太繁琐了,后来我注意到一个细节,每次我登陆后台,织梦系统都会记 ...
- springmvc下js控制表单提交(表单提交前检验,提交后获取json返回值)
这个问题我搞了四天,终于搞懂.因为对js很不熟悉.郁闷的是后台代码出错总可以设置断点调试,前端js代码出错只能通过浏览器提供一些运行数据来分析,很不习惯. 首先说下逻辑:这是一个注册功能,我希望,注册 ...
随机推荐
- #WEB安全基础 : HTML/CSS | 0x8.1CSS继承
CSS的一大特性——继承,怎么样没听说过吧,没了它我们修饰网页时就变得十足的麻烦 这是本节课准备的文件 这是others文件夹 先看看index.html,代码如下 <!DOCTYPE ...
- Dynamics 365中的应用程序介绍
本人微信和易信公众号:微软动态CRM专家罗勇 ,回复275或者20180630可方便获取本文,同时可以在第一间得到我发布的最新的博文信息,follow me!我的网站是 www.luoyong.me ...
- 【面向对象设计原则】之单一职责原则(SRP)
单一职责原则是面向对象原则五大原则中最简单,也是最重要的一个原则, 他的字面定义如下: 单一职责原则(Single Responsibility Principle, SRP): 一个类只负责一个功能 ...
- 41.Odoo产品分析 (四) – 工具板块(10) – 问卷(1)
查看Odoo产品分析系列--目录 在该模块下,可以创建问卷,收集答案,打印统计. 安装"问卷"模块,首页显示当前各个阶段中的问卷: 打开"开发者模式",能对 ...
- 测者的测试技术手册:自动化单元工具EvoSuie的代码覆盖报告
EvoSuite是由Sheffield等大学联合开发的一种开源工具,用于自动生成测试用例集,生成的测试用例均符合Junit的标准,可直接在Junit中运行.得到了Google和Yourkit的支持. ...
- 中文乱码之《字符编码:ASCII,Unicode 和 UTF-8》
参考文献:字符编码笔记:ASCII,Unicode 和 UTF-8 一.ASCII 码 我们知道,计算机内部,所有信息最终都是一个二进制值.每一个二进制位(bit)有0和1两种状态,因此八个二进制位就 ...
- js实现横向跑马灯效果
首先我们需要一个html代码的框架如下: <div style="position: absolute; top: 0px; left: 168px; width: 100%; mar ...
- Java调用windows命令
JAVA调用windows的cmd命令 用起来会让程序变得更加简洁明了,非常实用. 核心就是使用 Runtime类. cmd的xcopy就有很强大的文件夹,文件处理功能. 下面就以xcopy来说明,如 ...
- LeetCode算法题-Heaters(Java实现)
这是悦乐书的第239次更新,第252篇原创 01 看题和准备 今天介绍的是LeetCode算法题中Easy级别的第106题(顺位题号是475).冬天来了!您在比赛期间的第一份工作是设计一个固定温暖半径 ...
- 2星|《IT真相》:日本咨询师面对美国云服务的发展,对日本IT业哀其不争
IT真相-打通IT与商务的通路 I 作者是日本管理咨询师,对日本的IT和金融业了解比较多.书的内容是:作者看到美国的云服务发展壮大,日本IT业没能抓住机会,对日本IT业做了一些批评,比如不思进取,不了 ...