一 前言

  上一篇Jquery遮罩插件,想罩哪就罩哪! 结尾的预告终于来了。

  近期参与了一个针对内部员工个人信息收集的系统,其中有一个需求是在填写各个相关信息时,需要能动态的增加行当时公司有自己的解决方案 那就是用GridView 那个庞大的服务器控件,我一真就不怎么喜欢用服务器控件,于是极力说服PM用js来处理,并成功争取到了,先说下如果用GridView来处理的缺点,

1 生成的html代码会比较冗余,

2 每一个操作都会伴随页面回发,

3 每个操作都会刷新页面,这样的用户体验极差,就算用updatepanel也还是会有回发,

4 有点杀鸡用牛刀的感觉

那用js来处理以上的问题就都不存在了,重点是还能把js巩固一下(算是私心吧),由于项目的时间非常紧,而且又转成用js处理又没有相关的经验,整个过程压力还是很大的,免不了加班,但是做自己喜欢的事,就算加班我也是乐在其中

二 插件介绍

基本需求如下:

1 可以动态增加 删除行,

2 可以对行内数据进行校验,并支持自定义校验提示信息

3 能取到表格中的数据

4 能绑定后台数据到表格中

当然这只是大概的需求,还有很多小的细节就不写了,也不是本文的重点。下面详细写下每个功能的具体思路,当然我的肯定不是最好的思路,代码也肯定可再优化。

前后端数据交互过程如下:

前---后

前端取数据--->隐藏域---->后端取隐藏域值解析并存DB

后---前

后端取数据---->隐藏域----> 前端取隐藏域值添加到表格中

先看下效果

2.1  增加行 删除行

增加行

思路: 跳过第一行(也就是表头),复制第二行的html元素追加到表中,(在IE8中好像会将复制的行内文本值也会被追加到新的行中,这时需要遍历新的行将其清空)

代码如下

  1. //增加行
  2. $.fn.tables.addRow = function (gridId) {
  3. var tbRow = $("#" + gridId).find("tr").eq(1).html();
  4. var num = $("#" + gridId + " tr").length;
  5. $("#" + gridId).append("<tr id=" + num + ">" + tbRow + "</tr>");
  6. $("#" + gridId).find("tr").last().find("td").last().children().removeAttr("name").attr("value", "");
  7. };

  

删除行:

思路:点删除时通过当前元素找到其父元素"tr"然后再删除该"tr"元素

代码:

  1. //删除行
  2. //参数obj 当前对象
  3. $.fn.tables.deleteRow = function (obj) {
  4. var $this = $(obj);
  5. if ($this.parents("table").find("tr").length <= 2) {
  6. return false;
  7. }
  8. $this.parents("tr").remove();
  9. };

  2.2 取表格内数据: 

  思路:为了让前端的数据到后端容易解析,决定用json格式,将实体的属性名添加到元素的name属性中,组成结果时用元素的name属性做名称,value属性做值

遍历表格中每一行,并添加到一个数组中。取到的结果格式就是这样的 {"Relation":"Zery","RelativesName":"Zhang"},传到后台时将其序列化成对象就可以了

  1. <input name="RelativesName" type="text" style="width: 100px" class="required" />

代码:

  1. //取表格所有数据
  2. //返回值为一个数组,数组内每一个元素对应一行内的数据;
  3. $.fn.tables.getResult = function (gridId) {
  4.  
  5. var resultArray = new Array();
  6. $("#" + gridId).find("tr").slice(1).each(function () {
  7.  
  8. var trResult = "{";
  9.  
  10. $(this).find("td").each(function () {
  11. var $child = $(this).children();
  12.  
  13. if ($child.length > 1) {
  14. //td下有多个元素的(多个元素会用"|"拼接起来)
  15. //td下有多个元素的暂时禁用
  16. //$child.each(function () {
  17. // //alert($(this).attr("type"));
  18. // switch ($(this).attr("type")) {
  19. // case "text":
  20. // //alert($child.val() + "文件框的!");
  21.  
  22. // trResult += '"' + $(this).attr("name") + '"' + ":" + '"' + $(this).val() + '"' + ",";
  23. // break;
  24. // case "select":
  25. // // alert($(this).find("option:selected").text());
  26.  
  27. // trResult += '"' + $(this).attr("name") + '"' + ":" + '"' + $(this).find("option:selected").val() + '"' + ",";
  28. // break;
  29. // case "checkbox":
  30.  
  31. // if ($(this).attr("checked") === "checked") {
  32.  
  33. // trResult += '"' + $(this).attr("name") + '"' + ":" + '"' + $(this).val() + '"' + ",";
  34. // }
  35. // break;
  36.  
  37. // case "radio":
  38. // if ($(this).attr("checked") === "checked") {
  39.  
  40. // trResult += '"' + $(this).attr("propertys") + '"' + ":" + '"' + $(this).val() + '"' + ",";
  41. // }
  42. // break;
  43.  
  44. // default:
  45. // }
  46.  
  47. //});
  48. // trResult.push(valueStr);
  49.  
  50. } else {
  51. //td 下只有一个元素
  52. switch ($child.attr("type")) {
  53. case "text":
  54.  
  55. trResult += '"' + $child.attr("name") + '"' + ":" + '"' + $child.val() + '"' + ",";
  56. break;
  57. case "select":
  58.  
  59. trResult += '"' + $child.attr("name") + '"' + ":" + '"' + $child.find("option:selected").val() + '"' + ",";
  60. break;
  61. case "checkbox":
  62. if ($(this).attr("checked") === "checked") {
  63. trResult += '"' + $child.attr("name") + '"' + ":" + '"' + $child.val() + '"' + ",";
  64. } else {
  65. trResult += '"' + $child.attr("name") + '"' + ":0" + '"' + ",";
  66. }
  67. break;
  68. case "radio":
  69. if ($(this).attr("checked") === "checked") {
  70. trResult += '"' + $child.attr("propertys") + '"' + ":" + '"' + $child.val() + '"' + ",";
  71. } else {
  72. trResult += '"' + $child.attr("propertys") + '"' + ":0" + '"' + ",";
  73. }
  74. break;
  75.  
  76. default:
  77. }
  78. }
  79. });
  80.  
  81. trResult = trResult.substring(0, trResult.length - 1);
  82. resultArray.push(trResult + "}");
  83.  
  84. });
  85.  
  86. return resultArray;
  87. };

2.3 验证行数据:

思路:遍历每行中的元素根据元素类型来做判空处理,如果为空则在元素后追加提示信息,如果元素需要自定义错误信息时可以给元素加一个errormsg属性

代码:

  1. //验证行
  2. $.fn.tables.validateRow = function (gridId) {
  3.  
  4. //是否验证通过
  5. var isPass = true;
  6.  
  7. $("#" + gridId).find("tr").slice(1).each(function () {
  8.  
  9. $(this).find("td").each(function () {
  10. if ($(this).children().hasClass('text-error'))
  11. {
  12. return isPass = false;
  13. }
  14.  
  15. var $this = $(this).children();
  16.  
  17. if ($this.length > 1) {
  18. //checkbox选中数
  19. if ($(this).find("input[type='checkbox']").length > 0) {
  20. var checkedNum = $(this).find("input[type='checkbox'][checked]").length;
  21. if (checkedNum <= 0) {
  22. //TODO:复选框应该默认有选中项目不需要做验证
  23. // message = "此字段必填";
  24. //return message;
  25. }
  26. }
  27. //radio选中数
  28. if ($(this).find("input[type='radio']").length > 0) {
  29. var radioNum = $(this).find("input[type='radio'][checked]").length;
  30. if (radioNum <= 0) {
  31. //TODO:复选框应该默认有选中项目不需要做验证
  32. //message = "此字段必填";
  33. //return message;
  34. }
  35. }
  36. } else {
  37.  
  38. switch ($this.attr("type")) {
  39. case "text":
  40. var errorMsg = "此字段为必填项!";
  41. if ($this.hasClass("required")) {
  42. if ($.trim($this.val()) == "") {
  43.  
  44. isPass = false;
  45.  
  46. if ($this.attr("errormsg") == undefined) {
  47.  
  48. $this.addClass('error').after("<span class='help-block text-error'>" + errorMsg + "</span>");
  49. } else {
  50. errorMsg = $this.attr("errormsg");
  51. $this.addClass('error').after("<span class='help-block text-error'>" + errorMsg + "</span>");
  52. }
  53. }
  54. }
  55. if ($this.hasClass("detepickers")) {
  56. if ($.trim($this.val()) == "") {
  57. isPass = false;
  58. $this.addClass('error').after("<span class='help-block text-error'>" + errorMsg + "</span>");
  59. }
  60. }
  61. break;
  62. case "select":
  63. //默认有选中项不需要做验证
  64. //若选中项为“请选择”时可以根据选中值来验证
  65. break;
  66. default:
  67. }
  68. }
  69. });
  70.  
  71. });
  72. return isPass;
  73.  
  74. };

2.4 绑定数据

思路: 后台取到值后序列化成json后通过隐藏域传到前端,前端根据元素的name属性值与 Json串中的的key 做对比如果相等则赋值, 需要注意的是 所有的元素我都是用type属性来区分的 如果该元素没有type属性则需要自己加上 如 select 元素 需要加上 type='select'

代码:

  1. //绑定数据
  2. $.fn.tables.bindData = function (gridId, tbResult) {
  3.  
  4. //返回结果为一个数组
  5. // var result = $("#<%=hd"+gridId+".ClientID %>").val();
  6. var jsons = $.parseJSON(tbResult);
  7. if (jsons == null) {
  8. return;
  9. }
  10. var trHtml = $("#" + gridId).find("tr").slice(1).first().html();
  11.  
  12. //遍历行结果
  13. for (var i = 0; i < jsons.length; i++) {
  14. var trnum = $("#" + gridId).find("tr").slice(1).length - 1;
  15. if (i > trnum) {
  16. $("#" + gridId).append("<tr>" + trHtml + "</tr>");
  17.  
  18. }
  19.  
  20. //遍历行中每一列的key
  21. for (var key in jsons[i]) {
  22.  
  23. $("#" + gridId).find("tr").eq(i + 1).find("td").each(function () {
  24. var $child = $(this).children();
  25.  
  26. if ($child.attr("name") === key || $child.attr("propertys") === key) {
  27.  
  28. switch ($child.attr("type")) {
  29. case "text":
  30. $child.val(jsons[i][key]);
  31. break;
  32. case "select":
  33. //可以根据value 来设置选中项目
  34. $child.find("option").each(function () {
  35. var value = $(this).val();
  36. if (value === jsons[i][key]) {
  37. $(this).attr("selected", true);
  38. }
  39. });
  40.  
  41. break;
  42. case "checkbox":
  43. //可以根据value 来设置选中项目
  44.  
  45. $child.each(function () {
  46. var name = $(this).attr("name");
  47. if (name === key && $(this).val() === jsons[i][key]) {
  48. $(this).attr("checked", true);
  49. }
  50. });
  51.  
  52. case "radio":
  53. $child.each(function () {
  54. var name = $(this).attr("propertys");
  55. if (name === key && $(this).val() === jsons[i][key]) {
  56. $(this).attr("checked", true);
  57. }
  58. });
  59. break;
  60. case "a":
  61. case "button":
  62. $child.attr("value", jsons[i][key]);
  63. break;
  64. default:
  65. }
  66. }
  67. });
  68.  
  69. }
  70.  
  71. }
  72. };

以上都只是简单介绍思路,虽然写出来只有一点点,但是 当时在开发时在某些点却时想了很久,因为针对项目做了很多的特殊修改,所以这里只实现很基本的功能,代码也仅供参考,主要还是实现的思路

三  总结

   项目在几天前已经上线了,用户的反应还不错,也算对得起自己的付出吧,当时承担着项目延期的风险,决定用js来做的理由很简单,只是想把用户体验做的好一点。

做完后想想,有时候我们应该对自己要求高一点,不要总活在自己的舒适区,有挑战才能有成长。

源码示例下载:http://files.cnblogs.com/zery/WebApplication1.rar

如果您觉得本文有给您带来一点收获,不妨点个推荐,为我的付出支持一下,谢谢~

如果希望在技术的道路上能有更多的朋友,那就关注下我吧,让我们一起在技术的路上奔跑

jquery表格动态增删改及取数据绑定数据完整方案的更多相关文章

  1. jQuery EasyUI/TopJUI实现数据表格的增删改查功能(不写js,纯HTML实现!!!)

    jQuery EasyUI/TopJUI实现数据表格的增删改查功能(不写js,纯HTML实现!!!) 废话不多说,直接贴上代码 <table id="configEdatagrid&q ...

  2. JQuery实现表格动态增加行并对新行添加事件

    实现功能: 通常在编辑表格时表格的行数是不确定的,如果一次增加太多行可能导致页面内容太多,反应变慢:通过此程序实现表格动态增加行,一直保持最下面有多个空白行. 效果: 一:原始页面 二:表1增加新行并 ...

  3. 用AngularJS实现对表格的增删改查(仅限前端)

    <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...

  4. SQL server 创建 修改表格 及表格基本增删改查 及 高级查询 及 (数学、字符串、日期时间)函数[转]

    SQL server 创建 修改表格 及表格基本增删改查 及 高级查询 及 (数学.字符串.日期时间)函数   --创建表格 create table aa ( UserName varchar(50 ...

  5. EasyUI-在行内进行表格的增删改操作

    第一篇笔记中记录了如何实现表格的增删改,那个是点击之后跳出来一个对话框然后进行的,这里是在表格本身上进行的操作,也很简单,但是这里发现一个版本问题,也可以说是兼容性问题. 1.首先我们看引用的js和c ...

  6. easyui学习笔记2—在行内进行表格的增删改操作

    第一篇笔记中记录了如何实现表格的增删改,那个是点击之后跳出来一个对话框然后进行的,这里是在表格本身上进行的操作,也很简单,但是这里发现一个版本问题,也可以说是兼容性问题. 1.首先我们看引用的js和c ...

  7. 【原生】js实现表格的增删改查

    说在前面的,写给小白白的,大神请绕道~ 今天用原生js写一下动态表格的增删改查,主要是熟悉一下js的DOM操作. 首先,做一个表格,用来显示提交的数据,如图下: 此处,我添加了编号.姓名.密码.生日. ...

  8. js实现表格的增删改查

    这份代码实现了对表格的增加,删除,更改,查询. 点击一次添加按钮,表格会增加一行. 点击重置按钮,输入框的内容会被清空. 添加一行后,最后两格为更改和删除.点击更改,原有内容会各自显示在一个输入框内, ...

  9. 基于AT UI实现表格的增删改查遇到的坑

    基于AT UI实现表格的增删改查遇到的坑 坑一.表格数据加载的渲染报错 报错:Error in render: "TypeError: Cannot read property 'isChe ...

随机推荐

  1. (有趣)chrome不同浏览器版本对display:flex和溢出隐藏显示省略符号的bug

    项目中碰到一个十分有趣的情形: 布局要求是这样:右边创建新订单是固定宽度80px,左侧是自适应宽度,溢出隐藏.如下图. 这里布局不用说肯定使用display:flex的.左侧flex:1;右侧widt ...

  2. 谷歌浏览器下载地址 chrome最新版本 百度云地址

    每次下载更新谷歌浏览器是一件很蛋疼的事情.百度搜索"谷歌浏览器下载地址",居然有很多骗子网站,相信有很多不知所以的人中招了.收集了一些chrome的安装包,放在了百度云里面(打不开 ...

  3. 你所不知的 CSS ::before 和 ::after 伪元素用法

    CSS 有两个说不上常用的伪类 :before 和 :after,偶尔会被人用来添加些自定义格式什么的,但是它们的功用不仅于此.前几天发现了 Creative Link Effects 这个非常有意思 ...

  4. mysql时间加减函数

    先来看一个例子: select now(),now()+0; 可以看到now()函数可以返回一个时间也可以返回一个数字,就看大家如何使用.如果相对当前时间进行增加或减少,并不能直接加上或减去一个数字而 ...

  5. arcgis for flex展示GIS基本功能

    1.地图框选搜索: 这是空间查询,在地图上框选一定的范围,然后搜索出在这个范围之内的所有信息,搜索到的详细信息在列表框显示出来 2.属性查询: 3.数据库展示: 4.绘制图形: 地图上绘制各种不同形状 ...

  6. C#和ASP.NET之事件

    事件是一种用于类和类之间传递消息或触发新的行为的编程方式.通过提供事件的句柄,能够把控件和可执行的代码联系在一起, 如用户单击Button控件触发Click事件后就执行相应的事件处理代码. 事件的声明 ...

  7. SQLite学习笔记(六)&&共享缓存

    介绍 通常情况下,sqlite中每个连接都会一个独立的pager对象,pager对象中管理了该连接的缓存信息,通过pragma cache_size指令可以设置缓存大小,默认是2000个page,每个 ...

  8. 安装mysql后的基本配置

    1.添加环境变量 右键 此电脑->属性->高级系统设置->环境变量,在系统变量里面找到Path,双击.点击编辑,将mysql中bin文件的路径添加到最后一行,如:F:\AppSev\ ...

  9. springMVC基础controller类

    此文章是基于 搭建SpringMVC+Spring+Hibernate平台 功能:设置请求.响应对象:session.cookie操作:ajax访问返回json数据: 创建springMVC基础con ...

  10. 【Windows编程】系列第十一篇:多文档界面框架

    前面我们所举的例子中都是单文档界面框架,也就是说这个窗口里面的客户区就是一个文档界面,可以编写程序在里面输入或者绘制文本和图形输出,但是不能有出现多个文档的情况.比如下面的UltraEdit就是一个典 ...