前言:最近产品需要设计一套相对完整的组织架构的解决方案,由于组织架构涉及到层级关系,在表格里面展示层级关系,自然就要用到所谓的 treegrid。可惜的是,一些轻量级的表格组件本身并没有自带树形表格的功能,比如 bootstrapTable 就没有这个功能,怎么办呢?如果是 jqgrid、easyUI 的表格,treegrid 的效果可以说是轻而易举就能解决,而项目目前用的就是 bootstrapTable,不可能这个时候因为这个需求去换组件吧。博主分析了下,无非就两种解决方案:一种就是扩展 bootstrapTable 的 treegrid 功能;第二种就是再找一个单独的 treegrid 组件去实现这个功能。博主在网上找了下,找到了一个效果还不错的 treegrid 第三方组件,于是做了下封装,今天分享出来,供大家参考。
本文原创地址:http://www.cnblogs.com/landeanfen/p/6776152.html
最原始的效果
bootstrap 样式的效果
这个是组件最原始的效果,后面会告诉大家博主做了哪些封装以及加了哪些功能。
在此还是给出一个封装过的效果吧!
最后还是给出 github 上面一个开源的 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
(1)纵观组件的所有的 demo 和文档,基本都是说的我们直接写死的 table 标签,然后通过样式去确定父子关系,最后初始化得到效果,但大部分情况下,我们的表格数据都不是写死的,而是通过后台获取数据,然后将数据渲染到前端,最终得到我们想要的效果,如果根据组件目前的使用方式,我们得到一个集合数据之后,需要自己去拼接 tr、td 这些东西,这都是小事,最麻烦的是组件是有父子关系的,我们需要根据我们数据之间的关系转化为组件的父子关系,并且由于支持无限级,还涉及到数据的递归运算。这个复杂的过程是我们不想经常去做的,怎么办呢?最好的思路就是封装了,封装的时候麻烦一次,以后使用就简单了,可以说这是一件一劳永逸的事情。
(2)一般来说,既然是 treegrid,肯定会有表头,而这个表头是根据数据来动态显示的。组件自带的效果可以自己写死表头,但还是那句话,使用的灵活性太差。
由于以上两点,于是才有了今天的这篇文章。
首先我们将 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 = $('');
- var nowParentIndex = (parentIndex + (j++) + 1);
- tr.addClass('treegrid-' + nowParentIndex);
- tr.addClass('treegrid-parent-' + parentIndex);
- $.each(options.columns,
- function(index, column) {
- var 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 = $('');
- $.each(options.columns,
- function(i, item) {
- var th = $('');
- th.text(item.title);
- thr.append(th);
- });
- var thead = $('');
- thead.append(thr);
- target.append(thead);
- //构造表体
- var tbody = $('');
- var rootNode = target.getRootNodes(data);
- $.each(rootNode,
- function(i, item) {
- var tr = $('');
- tr.addClass('treegrid-' + (j + i));
- $.each(options.columns,
- function(index, column) {
- var 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、代码的封装思路基本是参考博主之前介绍组件的封装 http://www.cnblogs.com/landeanfen/p/5124542.html 这一篇里面的内容来的。
3、defaults 里面就是初始化组件的时候可以传递的参数,上述注释基本上写得比较清楚。id 和 parentId 两个参数主要是用来描述数据之间的父子级关系,后面我们介绍组件时候的时候你一看就能明白。
4、博主加了几个自认为很有用的属性和方法,应该能减少一些使用的麻烦。比如初始化组件的时候是否展开所有的子节点、添加 title、表格行的渐变色和表格边框等。
5、上述封装里面递归查找子节点的时候,每一次都需要遍历所有的数据去找子节点,效率偏低,如果你使用了类似 linq to js 之类的组件去操作 js 的集合,可以优化那部分代码,适当提高递归的效率。当然,如果你的结果集本身数据量不太大,这么写影响也不太大。
我们在界面上面引用需要的 CSS 和 js 文件
- <link href="~/Content/bootstrap/css/bootstrap.min.css" rel="stylesheet"
- />
- <link href="~/Content/jquery-treegrid-master/css/jquery.treegrid.css"
- 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 功能的思路博主已经有了,等有时间在下篇给出说明。
如果你觉得本文能够帮助你,可以右边随意 打赏 博主,也可以 推荐 进行精神鼓励。你的支持是博主继续坚持的不懈动力。
本文原创出处:http://www.cnblogs.com/landeanfen/
欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利
来源: http://www.cnblogs.com/landeanfen/p/6776152.html