這次和大家分享的是自己寫的一個table常用幾種展示格式的js插件取名為(table-shenniu),樣式使用的是bootstrap.min.css,還需要引用jquery.min.js包,這個插件由來的目的是項目中需要一個table格式的提交數據的頁面,功能有合併單元格,只能提交選中行數據,全選 ...
這次和大家分享的是自己寫的一個table常用幾種展示格式的js插件取名為(table-shenniu),樣式使用的是bootstrap.min.css,還需要引用jquery.min.js包,這個插件由來的目的是項目中需要一個table格式的提交數據的頁面,功能有合併單元格,只能提交選中行數據,全選功能,和一個下拉選功能;這幾種功能感覺朋友們肯定都會遇到,所以乾脆封裝一個插件,發佈出來說不定能幫到有些朋友快速完成任務哈哈,當然最主要的還是希望朋友們能相互交流裡面的代碼,邏輯,謝謝;中秋節就要到了,這裡提前預祝大家節日快樂,吃月餅的時候不要忘記了點個贊。
以上是個人的看法,下麵來正式分享今天的文章吧:
. 功能介紹與效果圖(認可的點個贊)
. 需求分析
. 插件主要代碼塊的說明
. 獲取table插件數據,並提交給後臺
. 插件源碼及幫助文檔
下麵一步一個腳印的來分享:
. 功能介紹與效果圖(認可的點個贊)
1.普通效果
2.合併表格
3.彙總
4.合併+彙總
5.展示選中行明細
. 需求分析
首先,咋們來看張圖:
如圖所示,這裡的乘客可能會選擇不同的產品,同時選擇的購買份數也可能改變,然後只能提交最後一列勾選上的數據這是上面的圖展示出來的功能信息;為了更好的用戶體驗顯然“乘客姓名”這一列需要吧相同名稱的數據合併;價格一列通常在用戶填寫表單中不會有彙總的操作,但是數據統計報表中一般就需要;還有這個產品列只有名稱,沒有更詳細描述信息,通常我們需要展示出來方便用戶瞭解更多的信息,一般我們直接在產品名稱對應的html元素使用title展示,這樣不友好,所以又有了點擊產品名稱,查看明細的需求;下麵我們來整合下需求:
1. table中每行需要checkbox選擇框和對應的份數下拉框select及全選按鈕
2. 重覆數據合併單元格
3. 彙總金額數字列
4. 明細描述
5. 還需要一個能隱藏產品Id或者乘客Id的元素(插件這裡定位一個隱藏列)
這個就是table列表需要滿足的需求,也是大眾化的需求吧
. 插件主要代碼塊的說明
首先,咋們來說下插件需要的固定格式的數據:列表頭json數據,列表行json集合數據格式;
列表頭json數據:
1 //測試用例-列表頭 2 var header = [ 3 4 { 5 "title": "產品名稱", 6 "name": "product", 7 "type": "label" 8 }, 9 { 10 "title": "銷售價", 11 "name": "sale", 12 "type": "label", 13 }, 14 { 15 "title": "份數", 16 "name": "num", 17 "type": "select", //如果是下拉框,這裡需要初始值val 18 "val": [ 19 { 20 "text": 1, 21 "val": 1 22 }, 23 { 24 "text": 2, 25 "val": 2 26 }, 27 { 28 "text": 3, 29 "val": 3 30 } 31 ] 32 }, 33 { 34 "title": "總額", 35 "name": "amount", 36 "type": "label" 37 }, 38 { 39 "title": "<input type='checkbox' name='cbAll' style='border: 0px; width: 20px; height: 20px;'/>", //如果是全選選擇框,這裡直接寫html元素 40 "name": "cb", 41 "type": "checkbox" 42 }, 43 { 44 "title": "保險Id", 45 "name": "productid", 46 "type": "hidden" 47 } 48 ];
列表頭數據註意點在於:
1. 如果"type": "select"類型,需要初始值val屬性的值,這樣每一行中才會出現一個下拉框
2. "type": "checkbox",如果列是覆選框,那麼頭部單元格一般是全選的覆選框,我們直接在頭部json定義
<input type='checkbox' name='cbAll' style='border: 0px; width: 20px; height: 20px;'/>
就行了,如果不需要全選框,直接定義成文字就行
3. 插件列支持的type類型有type:有label(文本),select(下拉框,如果是下拉框需要初始化下拉數據“val”),checkbox(選擇框,如果需要全選框直接寫html元素,預設自帶),hidden(隱藏域,保存每行唯一的值)
列表行json集合數據格式:
1 //測試用例-沒行數據 2 var data = [ 3 { "product": "神雕俠侶電影票", "sale": 30.00, "num": 1, "amount": 30.00, "cb": false, "productid": 2 }, 4 { "product": "搖搖樂門票", "sale": 30.00, "num": 2, "amount": 60.00, "cb": false, "productid": 1 }, 5 { "product": "神雕俠侶電影票", "sale": 30.00, "num": 1, "amount": 30.00, "cb": true, "productid": 2 }, 6 { "product": "搖搖樂門票", "sale": 30.00, "num": 3, "amount": 90.00, "cb": false, "productid": 1 } 7 ]; 8 9 data = [ 10 { "product": { "產品名稱": "神雕俠侶電影票", "描述": "神雕俠侶電影票,中秋節大放送,情侶們快來啊,只需一塊錢", "銷售價 ": 30.00 }, "sale": 30.00, "num": 1, "amount": 30.00, "cb": false, "productid": 1 }, 11 { "product": { "產品名稱": "搖搖樂門票", "描述": "搖搖樂門票,中秋節大放送,情侶們快來啊,只需一塊錢", "銷售價 ": 30.00 }, "sale": 30.00, "num": 2, "amount": 60.00, "cb": false, "productid": 2 }, 12 { "product": { "產品名稱": "楊過和小龍女電影票", "描述": "楊過和小龍女電影票,中秋節大放送,情侶們快來啊,只需一塊錢", "銷售價 ": 30.00 }, "sale": 30.00, "num": 1, "amount": 30.00, "cb": true, "productid": 3 }, 13 { "product": { "產品名稱": "四川一日行旅游券", "描述": "小編忙,沒時間維護" }, "sale": 30.00, "num": 3, "amount": 90.00, "cb": false, "productid": 4 }, 14 { "product": { "產品名稱": "四川一日行旅游券", "描述": "小編忙,沒時間維護" }, "sale": 30.00, "num": 1, "amount": 30.00, "cb": false, "productid": 5 } 15 ];
這裡需要註意的是這兩種數據結構,如果想要展示明細,那麼沒個單元格對應的值是一個{}對象,數據格式如:{"產品名稱":"四川一日行旅游券","描述":"小編忙,沒時間維護"}
,這裡的“產品名稱“將作為明細列名稱;如果只需要展示名稱不要明細,直接賦值成值就行了
其次,來看下可配置的參數說明,如下代碼:
var defOption = { id: "", //要顯示插件內容的div的Id (必需) header: header, //json格式列表頭 (必需) data: data, //json格式數據 (必需) cbAllName: "cbAll", //全選框Name cbName: "cb", //每行選框Name tableId: "table" + new Date().getTime(), //tableId 預設時間格式 isTotal: false, //是否彙總 (預設不彙總) outTotalCols: "", //不彙總列 多個格式如:1,2 isCombine: false, //是否合併單元格 (預設不合併) outCombineCols: "", //不合併單元格列 多個格式如:1,2 back: function () { console.log("這裡是回調"); } //回調函數 };
然後,代碼邏輯步奏為:初始化列表頭->初始化每行內容(每行載入的時候需要根據列表頭部的type來判斷應該載入什麼html元素控制項並且可以綁定初始化狀態值)->全選綁定事件->綁定某個需要展示明細的單元格,動態載入明細內容數據->執行彙總->執行合併單元格(此處需要註意的是,不需要先彙總在合併單元格,如果順序發生變化,彙總的格式將異常)->執行回調響應函數;這個就是主要的代碼邏輯;
. 獲取table插件數據,並提交給後臺
首先,table元素展示出來後,如果作為用戶提交的界面,還需要能獲取出用戶選擇的數據,並提交給後臺,我這裡列舉一個簡單的獲取列子,咋們可以直接在回調函數back中寫提交表單的代碼如:
1 var tbChoice = new tb_choice({ 2 id: "divShow", 3 data: data, 4 header: header, 5 outCols: "0,4,6", 6 isTotal: false, 7 back: function () { 8 9 $("#btnSave").click(function () { 10 11 var cbs = $("input[name='cb'][type='checkbox']:checked"); 12 if (cbs.length <= 0) { alert("請選擇保險"); return; } 13 14 var param = []; 15 $.each(cbs, function (index, item) { 16 var tr = $(this).parent().parent(); 17 var id = $(tr).find("[name='id']").val(); 18 var num = $(tr).find("[name='num'] option:selected").val(); 19 var productId = $(tr).find("[name='productid']").val(); 20 21 param.push({ id: id, num: num, productId: productId }); 22 }); 23 24 //請求後臺 25 $.post("Add.aspx", { op: orderId, t: "save", param: JSON.stringify(param) }, function (result01) { 26 27 var resultJson = JSON.parse(result01); 28 console.log(resultJson); 29 alert(resultJson.msg); 30 if (resultJson.status) { 31 32 location.reload(true); 33 } 34 }); 35 }); 36 } 37 });
我這裡直接在回調back函數裡面寫ajax提交給後臺數據,這裡使用遍歷table的每行需要的數據組合成json格式發送給後臺,用起來還是挺簡單的呢,因為獲取的使用通過name屬性來獲取元素的值,而name對應的都是最開始列表頭json數據的name,大家可以對比下
. 插件源碼及幫助文檔
首先,插件的源碼待會在結尾全部發佈,裡面分別有彙總方法,合併列方法,和一個String的擴展方法大家可以分開使用,朋友們有興趣的也可以看幫助文檔,根據文檔上面的頁面列子下載代碼也行;更多的展示效果可以來這裡看文檔table-shenniu;源碼如下:
1 /// <reference path="../jquery-1.10.2.min.js" /> 2 3 4 var tb_total = function () { 5 6 return { 7 8 //彙總 9 //tableId:table元素的Id 10 //outCols:排除不合併的列,多個使用‘,’隔開 11 sumTab: function (tableId, outCols) { 12 13 if (!outCols) { outCols = ""; } 14 15 var rows = $("#" + tableId + " tr"); 16 17 var colLen = $(rows).eq(1).find("td[class!='hide']").length; 18 var totalVal = []; 19 for (var i = 0; i < colLen; i++) { 20 totalVal.push("0"); 21 } 22 $.each(rows, function (i, item) { 23 24 var tds = $(item).find("td[class!='hide']"); 25 var crossVal = ""; 26 $(tds).each(function (i_td, item_td) { 27 28 var hVal = $(item_td).html(); 29 30 if (isNaN(hVal)) { 31 //非數字 32 totalVal[i_td] = ""; 33 } else { 34 if (totalVal[i_td].length > 0) { 35 36 //數字 37 totalVal[i_td] = (parseFloat(totalVal[i_td]) + parseFloat(hVal)).toFixed(2); 38 } else { crossVal = hVal; } 39 } 40 }); 41 }); 42 43 var totalHtml = []; 44 totalHtml.push("<tr style='background-color:#EBF0EE'>"); 45 for (var i in totalVal) { 46 47 totalHtml.push("<td align=\"center\">"); 48 49 if (i == 0) { 50 totalHtml.push("<font style='color:red'>合計</font>"); 51 totalHtml.push("</td>"); 52 continue; 53 } else if (outCols.length > 0) { 54 55 //表示存在排除列 56 if (("," + outCols + ",").indexOf("," + i + ",") > -1) { 57 totalHtml.push(""); 58 totalHtml.push("</td>"); 59 continue; 60 } 61 } 62 totalHtml.push(totalVal[i]); 63 totalHtml.push("</td>"); 64 } 65 totalHtml.push("</tr>"); 66 67 $("#" + tableId).append(totalHtml.join('')); 68 }, 69 70 //合併列 71 //tableId:table元素的Id 72 //outCols:排除不合併的列,多個使用‘,’隔開 73 uniteTab: function (tableId, col, outCols) { 74 75 if (!outCols) { outCols = ""; } 76 //col-- 需要合併單元格的列 1開始 77 var colLength = col; 78 var tb = document.getElementById(tableId); 79 if (!tb) { return; } 80 tb.style.display = ''; 81 var i = 0; 82 var j = 0; 83 var rowCount = tb.rows.length; // 行數 84 var colCount = tb.rows[0].cells.length; // 列數 85 var obj1 = null; 86 var obj2 = null; 87 //為每個單元格命名 88 for (i = 0; i < rowCount; i++) { 89 for (j = 0; j < colCount; j++) { 90 if (!tb.rows[i].cells[j]) { continue; } 91 tb.rows[i].cells[j].id = tableId + "tb__" + i.toString() + "_" + j.toString(); 92 } 93 } 94 //合併行 95 for (i = 0; i < colCount; i++) { 96 if (i == colLength) break; 97 //排除不合併列 98 if (("," + outCols + ",").indexOf("," + i + ",") > -1) { continue; } 99 100 obj1 = document.getElementById(tableId + "tb__0_" + i.toString()) 101 for (j = 1; j < rowCount; j++) { 102 obj2 = document.getElementById(tableId + "tb__" + j.toString() + "_" + i.toString()); 103 if (obj1.innerText == obj2.innerText) { 104 obj1.rowSpan++; 105 obj2.parentNode.removeChild(obj2); 106 } else { 107 obj1 = document.getElementById(tableId + "tb__" + j.toString() + "_" + i.toString()); 108 } 109 } 110 } 111 112 //合併列 113 for (i = 0; i < rowCount; i++) { 114 if (tb.rows[i] != null) { 115 colCount = tb.rows[i].cells.length; 116 obj1 = document.getElementById(tb.rows[i].cells[0].id); 117 if (obj1 != null) { 118 for (j = 1; j < colCount; j++) { 119 if (j >= colLength) break; 120 if (obj1.colSpan >= colLength) break; 121 122 if (tb.rows[i].cells[j]) { 123 obj2 = document.getElementById(tb.rows[i].cells[j].id); 124 125 if (obj1.innerText == obj2.innerText) { 126 obj1.colSpan++; 127 obj2.parentNode.removeChild(obj2); 128 j = j - 1; 129 } 130 else { 131 obj1 = obj2; 132 j = j + obj1.rowSpan; 133 } 134 } 135 } 136 } 137 } 138 } 139 140 } 141 } 142 } 143 144 //table 表插件,要求bootstrap.min.css樣式 145 var tb_choice = function (option) { 146 147 //測試用例-列表頭 148 var header = [ 149 150 { 151 "title": "