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代码出错只能通过浏览器提供一些运行数据来分析,很不习惯. 首先说下逻辑:这是一个注册功能,我希望,注册 ...
随机推荐
- 后端开发者的Vue学习之路(五)
目录 上节内容回顾 使用第三方组件库 如何发起请求 请求错误处理 请求带参 以get的方式带参: 以post的方式带参: 封装处理 请求的配置 axios实例 实现调用自定义函数来发起请求 抽取axi ...
- 博弈论进阶之Anti-SG游戏与SJ定理
前言 在上一节中,我们初步了解了一下SG函数与SG定理. 今天我们来分析一下SG游戏的变式--Anti-SG游戏以及它所对应的SG定理 首先从最基本的Anti-Nim游戏开始 Anti-Nim游戏是这 ...
- 文件类型解析漏洞防御与攻击(PHP)
简介: 解析漏洞主要是一些特殊文件被iis.Apache.Nginx等服务在某种情况下解释成脚本文件格式并得以执行而产生的漏洞,一般的思路都是用图片木马来欺骗服务器,上传webshell,达到提权的目 ...
- nginx sub模块替换文本
nginx的ngx_http_sub_module模块,可以用于修改网站响应内容中的字符串,如过滤敏感词.第三方模块ngx_http_substitutions_filter_module,弥补了ng ...
- Vue一个案例引发的递归组件的使用
今天我们继续使用 Vue 的撸我们的实战项目,只有在实战中我们才会领悟更多,光纸上谈兵然并卵,继上篇我们的<Vue一个案例引发的动态组件与全局事件绑定总结> 之后,今天来聊一聊我们如何在项 ...
- 记阿里云SLB后配置Nginx反向代理百度地图API的坑
需求: 百度的原始请求:https://api.map.baidu.com/place/v2/suggestion?query=s®ion=sc&city_limit=true& ...
- Linux如何查找某个时间点后生成的空文件
今天遇到一个特殊需求,需要找到某天(例如2017-04-13)以及这之后生成的空文件.那么这个要怎么处理呢?这个当然是用find命令来解决.如下所示, -mtime -5 表示查找距现在 5*24H ...
- MFC自绘菜单
自绘控件问题多多.本文以菜单为例. ①当要使用顶层菜单资源.对话框资源.状态栏资源等这3种资源的任何一种.那么CWinApp::InitInstance函数内部必须使用LoadFrame函数来加载资源 ...
- Java之IO流进阶篇:内存流,打印流,对象流
Java中的IO流,即为输入输出流.所谓输入输出流,都是相对于程序而言,程序就是这个参照物.一张图看懂输入输出流: 输入流抽象基类:InputStream,Reader 输出流抽象基类:OutputS ...
- windows环境:idea或者eclipse指定用户名操作hadoop集群
方法 在系统的环境变量或java JVM变量添加HADOOP_USER_NAME(具体值视情况而定). 比如:idea里面可以如下添加HADOOP_USER_NAME=hdfs 原理:直接看源码 /h ...