JS 组件系列之 bootstrap treegrid 组件封装过程
正文
前言:最近产品需要设计一套相对完整的组织架构的解决方案,由于组织架构涉及到层级关系,在表格里面展示层级关系,自然就要用到所谓的treegrid。可惜的是,一些轻量级的表格组件本身并没有自带树形表格的功能,比如bootstraptable就没有这个功能,怎么办呢?如果是jqgrid、easyui的表格,treegrid的效果可以说是轻而易举就能解决,而项目目前用的就是bootstraptable,不可能这个时候因为这个需求去换组件吧。博主分析了下,无非就两种解决方案:一种就是扩展bootstraptable的treegrid功能;第二种就是再找一个单独的treegrid组件去实现这个功能。在网上找了下,找到了一个效果还不错的treegrid第三方组件,于是做了下封装,今天分享出来,供大家参考。
一、开源的treegrid
1、组件效果预览
最原始的效果
bootstrap样式的效果
这个是组件最原始的效果,后面会告诉大家博主做了哪些封装以及加了哪些功能。
在此还是给出一个封装过的效果吧!
2、组件开源地址
最后还是给出github上面一个开源的treegrid组件。
github开源地址:
文档示例地址:
bootstrap样式的demo以及使用:
二、封装treegrid
1、组件封装的必要性
(1)纵观组件的所有的demo和文档,基本都是说的我们直接写死的table标签,然后通过样式去确定父子关系,最后初始化得到效果,但大部分情况下,我们的表格数据都不是写死的,而是通过后台获取数据,然后将数据渲染到前端,最终得到我们想要的效果,如果根据组件目前的使用方式,我们得到一个集合数据之后,需要自己去拼接tr、td这些东西,这都是小事,最麻烦的是组件是有父子关系的,我们需要根据我们数据之间的关系转化为组件的父子关系,并且由于支持无限级,还涉及到数据的递归运算。这个复杂的过程是我们不想经常去做的,怎么办呢?最好的思路就是封装了,封装的时候麻烦一次,以后使用就简单了,可以说这是一件一劳永逸的事情。
(2)一般来说,既然是treegrid,肯定会有表头,而这个表头是根据数据来动态显示的。组件自带的效果可以自己写死表头,但还是那句话,使用的灵活性太差。
由于以上两点,于是才有了今天的这篇文章。
2、组件封装代码示例
首先我们将treegrid组件下载并引用到我们的项目里面,然后向其目录里面加一个extension的文件夹,里面添加一个jquery.treegrid.extension.js的文件。
然后就是最重要的jquery.treegrid.extension.js文件的内容:
(function ($) { "use strict"; $.fn.treegriddata = function (options, param) { //如果是调用方法 if (typeof options == 'string') { return $.fn.treegriddata.methods[options](this, param); } //如果是初始化组件 options = $.extend({}, $.fn.treegriddata.defaults, options || {}); var target = $(this); debugger; //得到根节点 target.getrootnodes = function (data) { var result = []; $.each(data, function (index, item) { if (!item[options.parentcolumn]) { result.push(item); } }); return result; }; var j = 0; //递归获取子节点并且设置子节点 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; //构造表头 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); //构造表体 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 { //也可以通过defaults里面的data属性通过传递一个数据集合进来对组件进行初始化....有兴趣可以自己实现,思路和上述类似 } return target; }; $.fn.treegriddata.methods = { getallnodes: function (target, data) { return target.treegrid('getallnodes'); }, //组件的其他方法也可以进行类似封装........ }; $.fn.treegriddata.defaults = { id: 'id', parentcolumn: 'parentid', data: [], //构造table的数据集合 type: "get", //请求数据的ajax类型 url: null, //请求数据的ajax的url ajaxparams: {}, //请求数据的ajax的data属性 expandcolumn: null,//在哪一列上面显示展开按钮 expandall: true, //是否全部展开 striped: false, //是否各行渐变色 bordered: false, //是否显示边框 columns: [], expanderexpandedclass: 'glyphicon glyphicon-chevron-down',//展开的按钮的图标 expandercollapsedclass: 'glyphicon glyphicon-chevron-right'//缩起的按钮的图标 }; })(jquery);
代码说明
1、为了避免和源组件的初始化冲突,我们自定义的组件取了一个别名,叫 treegriddata 。我们使用组件的时候就通过treegriddata来进行初始化,如果你觉得这个名称不顺眼,可以自行修改。
2、代码的封装思路基本是参考博主之前介绍组件的封装 这一篇里面的内容来的。
3、defaults里面就是初始化组件的时候可以传递的参数,上述注释基本上写得比较清楚。id和parentid两个参数主要是用来描述数据之间的父子级关系,后面我们介绍组件时候的时候你一看就能明白。
4、博主加了几个自认为很有用的属性和方法,应该能减少一些使用的麻烦。比如初始化组件的时候是否展开所有的子节点、添加title、表格行的渐变色和表格边框等。
5、上述封装里面递归查找子节点的时候,每一次都需要遍历所有的数据去找子节点,效率偏低,如果你使用了类似linq to js之类的组件去操作js的集合,可以优化那部分代码,适当提高递归的效率。当然,如果你的结果集本身数据量不太大,这么写影响也不太大。
3、封装后的组件使用
我们在界面上面引用需要的css和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>
然后定义一个空的table标签
<table id="tb" ></table>
最后就是js初始化了
$(document).ready(function () { $('#tb').treegriddata({ id: 'id', parentcolumn: 'parentid', type: "get", //请求数据的ajax类型 url: '/testmvc/getdata', //请求数据的ajax的url ajaxparams: {}, //请求数据的ajax的data属性 expandcolumn: null,//在哪一列上面显示展开按钮 striped: true, //是否各行渐变色 bordered: true, //是否显示边框 //expandall: false, //是否全部展开 columns: [ { title: '机构名称', field: 'name' }, { title: '机构描述', field: 'desc' } ] }); });
当然啦,还得配上后台的取数据的方法
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 = "百度事业部", 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 = "搜狐事业部", desc = "it", parentid = 6 }); result.add(new { id = 10, name = "搜狐事业子部", desc = "it", parentid = 9 }); return json(result, jsonrequestbehavior.allowget); } }
这里一看应该就能明白组件defaults里面的id和parentcolumn的作用了吧。记得jqgrid里面使用treeview的时候用到了一个level用来判断是哪一级别的节点,博主觉得这样硬性要求返回数据里面加一个level属性有点不妥,所以我们约定如果当前记录的parentid为null或者空字符串的时候,这个节点就是根节点,然后根据根节点去递归找子节点。
使用后的各种效果示例如下。
初始化的时候配置expandall: false得到的效果
增加隔行变色striped: true
增加表格边框bordered: true
综合效果
三、总结
至此本文就结束了,没有什么太高大上的技术,就是简单将一个第三方组件进行了一些封装,使得其使用起来更加方便而已。如果你项目中也正在为treegrid而纠结,何不试试呢。其实扩展bootstraptable的treegrid功能的思路博主已经有了,等有时间在下篇给出说明。
以上所述是小编给大家介绍的js 组件系统之 bootstrap treegrid 组件封装过程,希望对大家有所帮助
推荐阅读
-
JS 组件系列之Bootstrap Table的冻结列功能彻底解决高度问题
-
JS 组件系列之Bootstrap Table 冻结列功能IE浏览器兼容性问题解决方案
-
BootStrap学习系列之布局组件(下拉,按钮组[toolbar],上拉)
-
JS 组件系列之 bootstrap treegrid 组件封装过程
-
JS组件系列之JS组件封装过程详解
-
JS组件系列之MVVM组件构建自己的Vue组件
-
JS组件系列之MVVM组件 vue 30分钟搞定前端增删改查
-
JS 组件系列之BootstrapTable的treegrid功能
-
JS组件系列之Gojs组件 前端图形化插件之利器
-
JS组件系列--Bootstrap 树控件使用经验分享_html/css_WEB-ITnose