JS 組件系列之 bootstrap treegrid 組件封裝過(guò)程
正文
前言:最近產(chǎn)品需要設(shè)計(jì)一套相對(duì)完整的組織架構(gòu)的解決方案,由于組織架構(gòu)涉及到層級(jí)關(guān)系,在表格里面展示層級(jí)關(guān)系,自然就要用到所謂的treegrid??上У氖?,一些輕量級(jí)的表格組件本身并沒有自帶樹形表格的功能,比如bootstrapTable就沒有這個(gè)功能,怎么辦呢?如果是jqgrid、easyUI的表格,treegrid的效果可以說(shuō)是輕而易舉就能解決,而項(xiàng)目目前用的就是bootstrapTable,不可能這個(gè)時(shí)候因?yàn)檫@個(gè)需求去換組件吧。博主分析了下,無(wú)非就兩種解決方案:一種就是擴(kuò)展bootstrapTable的treegrid功能;第二種就是再找一個(gè)單獨(dú)的treegrid組件去實(shí)現(xiàn)這個(gè)功能。在網(wǎng)上找了下,找到了一個(gè)效果還不錯(cuò)的treegrid第三方組件,于是做了下封裝,今天分享出來(lái),供大家參考。
一、開源的treegrid
1、組件效果預(yù)覽
最原始的效果
bootstrap樣式的效果
這個(gè)是組件最原始的效果,后面會(huì)告訴大家博主做了哪些封裝以及加了哪些功能。
在此還是給出一個(gè)封裝過(guò)的效果吧!
2、組件開源地址
最后還是給出github上面一個(gè)開源的treegrid組件。
github開源地址:https://github.com/maxazan/jquery-treegrid
文檔示例地址:http://maxazan.github.io/jquery-treegrid/
bootstrap樣式的demo以及使用:http://maxazan.github.io/jquery-treegrid/examples/example-bootstrap-3.html
二、封裝treegrid
1、組件封裝的必要性
(1)縱觀組件的所有的demo和文檔,基本都是說(shuō)的我們直接寫死的table標(biāo)簽,然后通過(guò)樣式去確定父子關(guān)系,最后初始化得到效果,但大部分情況下,我們的表格數(shù)據(jù)都不是寫死的,而是通過(guò)后臺(tái)獲取數(shù)據(jù),然后將數(shù)據(jù)渲染到前端,最終得到我們想要的效果,如果根據(jù)組件目前的使用方式,我們得到一個(gè)集合數(shù)據(jù)之后,需要自己去拼接tr、td這些東西,這都是小事,最麻煩的是組件是有父子關(guān)系的,我們需要根據(jù)我們數(shù)據(jù)之間的關(guān)系轉(zhuǎn)化為組件的父子關(guān)系,并且由于支持無(wú)限級(jí),還涉及到數(shù)據(jù)的遞歸運(yùn)算。這個(gè)復(fù)雜的過(guò)程是我們不想經(jīng)常去做的,怎么辦呢?最好的思路就是封裝了,封裝的時(shí)候麻煩一次,以后使用就簡(jiǎn)單了,可以說(shuō)這是一件一勞永逸的事情。
(2)一般來(lái)說(shuō),既然是treegrid,肯定會(huì)有表頭,而這個(gè)表頭是根據(jù)數(shù)據(jù)來(lái)動(dòng)態(tài)顯示的。組件自帶的效果可以自己寫死表頭,但還是那句話,使用的靈活性太差。
由于以上兩點(diǎn),于是才有了今天的這篇文章。
2、組件封裝代碼示例
首先我們將treegrid組件下載并引用到我們的項(xiàng)目里面,然后向其目錄里面加一個(gè)extension的文件夾,里面添加一個(gè)jquery.treegrid.extension.js的文件。
然后就是最重要的jquery.treegrid.extension.js文件的內(nèi)容:
(function ($) { "use strict"; $.fn.treegridData = function (options, param) { //如果是調(diào)用方法 if (typeof options == 'string') { return $.fn.treegridData.methods[options](this, param); } //如果是初始化組件 options = $.extend({}, $.fn.treegridData.defaults, options || {}); var target = $(this); debugger; //得到根節(jié)點(diǎn) target.getRootNodes = function (data) { var result = []; $.each(data, function (index, item) { if (!item[options.parentColumn]) { result.push(item); } }); return result; }; var j = 0; //遞歸獲取子節(jié)點(diǎn)并且設(shè)置子節(jié)點(diǎn) target.getChildNodes = function (data, parentNode, parentIndex, tbody) { $.each(data, function (i, item) { if (item[options.parentColumn] == parentNode[options.id]) { var tr = $('<tr></tr>'); var nowParentIndex = (parentIndex + (j++) + 1); tr.addClass('treegrid-' + nowParentIndex); tr.addClass('treegrid-parent-' + parentIndex); $.each(options.columns, function (index, column) { var td = $('<td></td>'); td.text(item[column.field]); tr.append(td); }); tbody.append(tr); target.getChildNodes(data, item, nowParentIndex, tbody) } }); }; target.addClass('table'); if (options.striped) { target.addClass('table-striped'); } if (options.bordered) { target.addClass('table-bordered'); } if (options.url) { $.ajax({ type: options.type, url: options.url, data: options.ajaxParams, dataType: "JSON", success: function (data, textStatus, jqXHR) { debugger; //構(gòu)造表頭 var thr = $('<tr></tr>'); $.each(options.columns, function (i, item) { var th = $('<th style="padding:10px;"></th>'); th.text(item.title); thr.append(th); }); var thead = $('<thead></thead>'); thead.append(thr); target.append(thead); //構(gòu)造表體 var tbody = $('<tbody></tbody>'); var rootNode = target.getRootNodes(data); $.each(rootNode, function (i, item) { var tr = $('<tr></tr>'); tr.addClass('treegrid-' + (j + i)); $.each(options.columns, function (index, column) { var td = $('<td></td>'); td.text(item[column.field]); tr.append(td); }); tbody.append(tr); target.getChildNodes(data, item, (j + i), tbody); }); target.append(tbody); target.treegrid({ expanderExpandedClass: options.expanderExpandedClass, expanderCollapsedClass: options.expanderCollapsedClass }); if (!options.expandAll) { target.treegrid('collapseAll'); } } }); } else { //也可以通過(guò)defaults里面的data屬性通過(guò)傳遞一個(gè)數(shù)據(jù)集合進(jìn)來(lái)對(duì)組件進(jìn)行初始化....有興趣可以自己實(shí)現(xiàn),思路和上述類似 } return target; }; $.fn.treegridData.methods = { getAllNodes: function (target, data) { return target.treegrid('getAllNodes'); }, //組件的其他方法也可以進(jìn)行類似封裝........ }; $.fn.treegridData.defaults = { id: 'Id', parentColumn: 'ParentId', data: [], //構(gòu)造table的數(shù)據(jù)集合 type: "GET", //請(qǐng)求數(shù)據(jù)的ajax類型 url: null, //請(qǐng)求數(shù)據(jù)的ajax的url ajaxParams: {}, //請(qǐng)求數(shù)據(jù)的ajax的data屬性 expandColumn: null,//在哪一列上面顯示展開按鈕 expandAll: true, //是否全部展開 striped: false, //是否各行漸變色 bordered: false, //是否顯示邊框 columns: [], expanderExpandedClass: 'glyphicon glyphicon-chevron-down',//展開的按鈕的圖標(biāo) expanderCollapsedClass: 'glyphicon glyphicon-chevron-right'//縮起的按鈕的圖標(biāo) }; })(jQuery);
代碼說(shuō)明
1、為了避免和源組件的初始化沖突,我們自定義的組件取了一個(gè)別名,叫 treegridData 。我們使用組件的時(shí)候就通過(guò)treegridData來(lái)進(jìn)行初始化,如果你覺得這個(gè)名稱不順眼,可以自行修改。
2、代碼的封裝思路基本是參考博主之前介紹組件的封裝 http://www.dbjr.com.cn/article/112472.htm這一篇里面的內(nèi)容來(lái)的。
3、defaults里面就是初始化組件的時(shí)候可以傳遞的參數(shù),上述注釋基本上寫得比較清楚。id和parentId兩個(gè)參數(shù)主要是用來(lái)描述數(shù)據(jù)之間的父子級(jí)關(guān)系,后面我們介紹組件時(shí)候的時(shí)候你一看就能明白。
4、博主加了幾個(gè)自認(rèn)為很有用的屬性和方法,應(yīng)該能減少一些使用的麻煩。比如初始化組件的時(shí)候是否展開所有的子節(jié)點(diǎn)、添加title、表格行的漸變色和表格邊框等。
5、上述封裝里面遞歸查找子節(jié)點(diǎn)的時(shí)候,每一次都需要遍歷所有的數(shù)據(jù)去找子節(jié)點(diǎn),效率偏低,如果你使用了類似linq to js之類的組件去操作js的集合,可以優(yōu)化那部分代碼,適當(dāng)提高遞歸的效率。當(dāng)然,如果你的結(jié)果集本身數(shù)據(jù)量不太大,這么寫影響也不太大。
3、封裝后的組件使用
我們?cè)诮缑嫔厦嬉眯枰腸ss和js文件
<link href="~/Content/bootstrap/css/bootstrap.min.css" rel="external nofollow" rel="stylesheet" /> <link href="~/Content/jquery-treegrid-master/css/jquery.treegrid.css" rel="external nofollow" rel="stylesheet" /> <script src="~/Scripts/jquery-1.10.2.min.js"></script> <script src="~/Content/bootstrap/js/bootstrap.min.js"></script> <script src="~/Content/jquery-treegrid-master/js/jquery.treegrid.min.js"></script> <script src="~/Content/jquery-treegrid-master/js/jquery.treegrid.bootstrap3.js"></script> <script src="~/Content/jquery-treegrid-master/extension/jquery.treegrid.extension.js"></script>
然后定義一個(gè)空的table標(biāo)簽
<table id="tb" ></table>
最后就是js初始化了
$(document).ready(function () { $('#tb').treegridData({ id: 'Id', parentColumn: 'ParentId', type: "GET", //請(qǐng)求數(shù)據(jù)的ajax類型 url: '/TestMVC/GetData', //請(qǐng)求數(shù)據(jù)的ajax的url ajaxParams: {}, //請(qǐng)求數(shù)據(jù)的ajax的data屬性 expandColumn: null,//在哪一列上面顯示展開按鈕 striped: true, //是否各行漸變色 bordered: true, //是否顯示邊框 //expandAll: false, //是否全部展開 columns: [ { title: '機(jī)構(gòu)名稱', field: 'Name' }, { title: '機(jī)構(gòu)描述', field: 'Desc' } ] }); });
當(dāng)然啦,還得配上后臺(tái)的取數(shù)據(jù)的方法
public class TestMVCController : Controller {public JsonResult GetData() { var result = new List<object>(); result.Add(new { Id = 1, Name = "百度科技", Desc = "搜索巨頭"}); result.Add(new { Id = 2, Name = "百度事業(yè)部", Desc = "搜索巨頭",ParentId=1 }); result.Add(new { Id = 3, Name = "百度人事部", Desc = "搜索巨頭", ParentId = 1 }); result.Add(new { Id = 11, Name = "百度HH部", Desc = "搜索巨頭", ParentId = 2 }); result.Add(new { Id = 4, Name = "百度行政", Desc = "搜索巨頭", ParentId = 1 }); result.Add(new { Id = 5, Name = "百度YY部", Desc = "搜索巨頭", ParentId = 1 }); result.Add(new { Id = 12, Name = "百度BB部", Desc = "搜索巨頭", ParentId = 2 }); result.Add(new { Id = 6, Name = "搜狐科技", Desc = "IT" }); result.Add(new { Id = 7, Name = "搜狐信息部", Desc = "IT", ParentId = 6 }); result.Add(new { Id = 8, Name = "搜狐人事", Desc = "IT", ParentId = 6 }); result.Add(new { Id = 9, Name = "搜狐事業(yè)部", Desc = "IT", ParentId = 6 }); result.Add(new { Id = 10, Name = "搜狐事業(yè)子部", Desc = "IT", ParentId = 9 }); return Json(result, JsonRequestBehavior.AllowGet); } }
這里一看應(yīng)該就能明白組件defaults里面的id和parentColumn的作用了吧。記得jqgrid里面使用treeview的時(shí)候用到了一個(gè)level用來(lái)判斷是哪一級(jí)別的節(jié)點(diǎn),博主覺得這樣硬性要求返回?cái)?shù)據(jù)里面加一個(gè)level屬性有點(diǎn)不妥,所以我們約定如果當(dāng)前記錄的parentId為null或者空字符串的時(shí)候,這個(gè)節(jié)點(diǎn)就是根節(jié)點(diǎn),然后根據(jù)根節(jié)點(diǎn)去遞歸找子節(jié)點(diǎn)。
使用后的各種效果示例如下。
初始化的時(shí)候配置expandAll: false得到的效果
增加隔行變色striped: true
增加表格邊框bordered: true
綜合效果
三、總結(jié)
至此本文就結(jié)束了,沒有什么太高大上的技術(shù),就是簡(jiǎn)單將一個(gè)第三方組件進(jìn)行了一些封裝,使得其使用起來(lái)更加方便而已。如果你項(xiàng)目中也正在為treegrid而糾結(jié),何不試試呢。其實(shí)擴(kuò)展bootstrapTable的treegrid功能的思路博主已經(jīng)有了,等有時(shí)間在下篇給出說(shuō)明。
以上所述是小編給大家介紹的JS 組件系統(tǒng)之 bootstrap treegrid 組件封裝過(guò)程,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
- bootstrap table表格插件使用詳解
- Angualrjs和bootstrap相結(jié)合實(shí)現(xiàn)數(shù)據(jù)表格table
- bootstrap table實(shí)現(xiàn)單擊單元格可編輯功能
- BootstrapTable refresh 方法使用實(shí)例簡(jiǎn)單介紹
- bootstrap jquery dataTable 異步ajax刷新表格數(shù)據(jù)的實(shí)現(xiàn)方法
- bootstrap——bootstrapTable實(shí)現(xiàn)隱藏列的示例
- JS 組件系列之BootstrapTable的treegrid功能
相關(guān)文章
JavaScript中的JSON轉(zhuǎn)為Python可讀取
本文主要介紹了JavaScript中的JSON轉(zhuǎn)為Python可讀取,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-01-01JS繼承實(shí)現(xiàn)方法及優(yōu)缺點(diǎn)詳解
這篇文章主要介紹了JS繼承實(shí)現(xiàn)方法及優(yōu)缺點(diǎn)詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-09-09動(dòng)態(tài)加載腳本提升javascript性能
動(dòng)態(tài)加載腳本可以有效提升javascript性能,下面有個(gè)不錯(cuò)的示例,大家可以參考下2014-02-02Three.js利用orbit controls插件(軌道控制)控制模型交互動(dòng)作詳解
這篇文章主要給大家介紹了關(guān)于Three.js利用orbit controls插件,也就是軌道控制來(lái)控制模型交互動(dòng)作的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起看看吧。2017-09-09javascript實(shí)現(xiàn)字符串反轉(zhuǎn)的方法
這篇文章主要介紹了javascript實(shí)現(xiàn)字符串反轉(zhuǎn)的方法,實(shí)例分析了javascript實(shí)現(xiàn)字符串反轉(zhuǎn)的技巧,需要的朋友可以參考下2015-02-02Phaser.js實(shí)現(xiàn)簡(jiǎn)單的跑酷游戲附源碼下載
這篇文章主要介紹了Phaser.js實(shí)現(xiàn)簡(jiǎn)單的跑酷游戲附源碼下載,需要的朋友可以參考下2018-10-10