• 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自定义表单提交处理方案的更多相关文章

  1. DedeCMS实现自定义表单提交后发送指定QQ邮箱法

    https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&tn=monline_3_dg&wd=dedecms 邮箱&oq=d ...

  2. DedeCMS实现自定义表单提交后发送指定QQ邮箱的方法

    如月cruyue在做DedeCMS自定义表单发送邮箱的教程,发现大部分都是在php文件里写死固定字段内容,这样虽然也能实现自定义表单提交后发送指定邮箱,但是很不智能,如月cruyue想要一个我们自定义 ...

  3. phpcms v9自定义表单提交后返回上一页实现方法

    PHPcms v9中提交自定义表单后默认都是回到首页的,是不是感觉很不爽! 接下来,就说下phpcms v9自定义表单提交后返回上一页实现方法. 1.找到这个文件 phpcms\modules\for ...

  4. dedecms自定义表单提交成功后提示信息修改和跳转链接修改

    我们在用dedecms自定义表单提交成功后提示信息一般是"Dedecms 提示信息",这个要怎么改成自己想要的文字呢?还有就是提示页停留时间,目前估计就2秒,太快了,要如何设置长点 ...

  5. jquery.form.js 让表单提交更优雅

    jquery.form.js 让表单提交更优雅.可以页面不刷新提交表单,比jQuery的ajax提交要功能强大. 1.引入 <script src="/src/jquery-1.9.1 ...

  6. [转]django自定义表单提交

    原文网址:http://www.cnblogs.com/retop/p/4677148.html 注:本人使用的Django1.8.3版本进行测试 除了使用Django内置表单,有时往往我们需要自定义 ...

  7. Django初体验(一):自定义表单提交

    注:本人使用的Django1.8.3版本进行测试 除了使用Django内置表单,有时往往我们需要自定义表单.对于自定义表单Post方式提交往往会带来由CSRF(跨站请求伪造)产生的错误"CS ...

  8. dedecms自定义表单提交获取时间跟ip地址

    相信大家在用织梦做网站的时候都用过自定义表单做留言,但是如何查看客户什么时间填写的表单,和客户的IP地址呢? 我在网上找了很多JS文件,但太繁琐了,后来我注意到一个细节,每次我登陆后台,织梦系统都会记 ...

  9. springmvc下js控制表单提交(表单提交前检验,提交后获取json返回值)

    这个问题我搞了四天,终于搞懂.因为对js很不熟悉.郁闷的是后台代码出错总可以设置断点调试,前端js代码出错只能通过浏览器提供一些运行数据来分析,很不习惯. 首先说下逻辑:这是一个注册功能,我希望,注册 ...

随机推荐

  1. Dynamics 365-为什么CRM环境Workflow执行了多次?

    Workflow执行了多次,这个现象如果排除业务逻辑冲突,人为失误等原因,可能有的人遇到的并不多,但是笔者时不时还能遇到这种情况,所以在这里做个记录,也给遇到相同问题的人一个解决的方法. 当一个Wor ...

  2. 大湾区联动:广州深圳助力东莞.NET俱乐部首次线下活动

    新年伊始,经过一个寒冬考验后的.NET社区热情不减,长沙.南京.合肥.东莞先后建立以微信为主要平台的线上.NET社区.并相继开始筹划和组织各地区的首次线下活动.东莞作为粤港澳大湾区的腹地,制造业基地, ...

  3. JButton 按钮,JRadioJButton单选按钮,JChectBox复选框

    一. [按钮JButton] //导入Java类 import javax.swing.*;import java.awt.*;import java.awt.event.ActionEvent;im ...

  4. 使用Linq的泛型功能

    泛型数据访问类: 业务抽象类使用数据访问类: 业务类继承业务抽象类: 使用业务类:

  5. Linux内核同步机制之(五):Read Write spin lock【转】

    一.为何会有rw spin lock? 在有了强大的spin lock之后,为何还会有rw spin lock呢?无他,仅仅是为了增加内核的并发,从而增加性能而已.spin lock严格的限制只有一个 ...

  6. c/c++ linux 进程 fork wait函数

    linux 进程 fork wait函数 fork:创建子进程 wait:父进程等待子进程结束,并销毁子进程,如果父进程不调用wait函数,子进程就会一直留在linux内核中,变成了僵尸进程. for ...

  7. Centos7上安装docker (转)

    Centos7上安装docker Docker从1.13版本之后采用时间线的方式作为版本号,分为社区版CE和企业版EE. 社区版是免费提供给个人开发者和小型团体使用的,企业版会提供额外的收费服务,比如 ...

  8. windows批处理添加AD域账户

    因为要用个批处理命令在Windows Server里面批量添加域用户,所以需要使用批处理命令. 我这篇是纯新手教程,在百度上搜了一些批处理命令感觉属于进阶教程,研究了两天才完成我要完成的目标. 下面从 ...

  9. 正益工作能担起PaaS+SaaS的未来探索吗?

    没有竞争,行业没有未来.不参与竞争,企业没有未来.中国企业的类型纷繁复杂,也决定了企业的多样化需求.云计算和移动化的双重叠加,企业管理需要重新梳理,企业业务创新日益频繁,个性化需求日益突出,软件服务商 ...

  10. .NET CORE微服务中CONSUL的相关使用

    .NET CORE微服务中CONSUL的相关使用 1.consul在微服务中的作用 consul主要做三件事:1.提供服务到ip的注册 2.提供ip到服务地址的列表查询 3.对提供服务方做健康检查(定 ...