JS组件系列——自己动手封装bootstrap-treegrid组件

蔚落 2022-06-17 14:15 308阅读 0赞

一、开源的treegrid

回到顶部

1、组件效果预览

最原始的效果

459756-20170427200832584-538330588.png

bootstrap样式的效果

459756-20170427200855694-147617581.png

459756-20170427200905928-734283407.png

这个是组件最原始的效果,后面会告诉大家博主做了哪些封装以及加了哪些功能。

在此还是给出一个封装过的效果吧!

459756-20170427210638053-1519646105.png

回到顶部

2、组件开源地址

最后还是给出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

回到顶部

二、封装treegrid

回到顶部

1、组件封装的必要性

(1)纵观组件的所有的demo和文档,基本都是说的我们直接写死的table标签,然后通过样式去确定父子关系,最后初始化得到效果,但大部分情况下,我们的表格数据都不是写死的,而是通过后台获取数据,然后将数据渲染到前端,最终得到我们想要的效果,如果根据组件目前的使用方式,我们得到一个集合数据之后,需要自己去拼接tr、td这些东西,这都是小事,最麻烦的是组件是有父子关系的,我们需要根据我们数据之间的关系转化为组件的父子关系,并且由于支持无限级,还涉及到数据的递归运算。这个复杂的过程是我们不想经常去做的,怎么办呢?最好的思路就是封装了,封装的时候麻烦一次,以后使用就简单了,可以说这是一件一劳永逸的事情。

(2)一般来说,既然是treegrid,肯定会有表头,而这个表头是根据数据来动态显示的。组件自带的效果可以自己写死表头,但还是那句话,使用的灵活性太差。

由于以上两点,于是才有了今天的这篇文章。

回到顶部

2、组件封装代码示例

首先我们将treegrid组件下载并引用到我们的项目里面,然后向其目录里面加一个extension的文件夹,里面添加一个jquery.treegrid.extension.js的文件。

459756-20170427204320647-1305518790.png

然后就是最重要的jquery.treegrid.extension.js文件的内容:

复制代码

  1. (function ($) {
  2. "use strict";
  3. $.fn.treegridData = function (options, param) {
  4. //如果是调用方法
  5. if (typeof options == 'string') {
  6. return $.fn.treegridData.methods[options](this, param);
  7. }
  8. //如果是初始化组件
  9. options = $.extend({}, $.fn.treegridData.defaults, options || {});
  10. var target = $(this);
  11. debugger;
  12. //得到根节点
  13. target.getRootNodes = function (data) {
  14. var result = [];
  15. $.each(data, function (index, item) {
  16. if (!item[options.parentColumn]) {
  17. result.push(item);
  18. }
  19. });
  20. return result;
  21. };
  22. var j = 0;
  23. //递归获取子节点并且设置子节点
  24. target.getChildNodes = function (data, parentNode, parentIndex, tbody) {
  25. $.each(data, function (i, item) {
  26. if (item[options.parentColumn] == parentNode[options.id]) {
  27. var tr = $('<tr></tr>');
  28. var nowParentIndex = (parentIndex + (j++) + 1);
  29. tr.addClass('treegrid-' + nowParentIndex);
  30. tr.addClass('treegrid-parent-' + parentIndex);
  31. $.each(options.columns, function (index, column) {
  32. var td = $('<td></td>');
  33. td.text(item[column.field]);
  34. tr.append(td);
  35. });
  36. tbody.append(tr);
  37. target.getChildNodes(data, item, nowParentIndex, tbody)
  38. }
  39. });
  40. };
  41. target.addClass('table');
  42. if (options.striped) {
  43. target.addClass('table-striped');
  44. }
  45. if (options.bordered) {
  46. target.addClass('table-bordered');
  47. }
  48. if (options.url) {
  49. $.ajax({
  50. type: options.type,
  51. url: options.url,
  52. data: options.ajaxParams,
  53. dataType: "JSON",
  54. success: function (data, textStatus, jqXHR) {
  55. debugger;
  56. //构造表头
  57. var thr = $('<tr></tr>');
  58. $.each(options.columns, function (i, item) {
  59. var th = $('<th style="padding:10px;"></th>');
  60. th.text(item.title);
  61. thr.append(th);
  62. });
  63. var thead = $('<thead></thead>');
  64. thead.append(thr);
  65. target.append(thead);
  66. //构造表体
  67. var tbody = $('<tbody></tbody>');
  68. var rootNode = target.getRootNodes(data);
  69. $.each(rootNode, function (i, item) {
  70. var tr = $('<tr></tr>');
  71. tr.addClass('treegrid-' + (j + i));
  72. $.each(options.columns, function (index, column) {
  73. var td = $('<td></td>');
  74. td.text(item[column.field]);
  75. tr.append(td);
  76. });
  77. tbody.append(tr);
  78. target.getChildNodes(data, item, (j + i), tbody);
  79. });
  80. target.append(tbody);
  81. target.treegrid({
  82. expanderExpandedClass: options.expanderExpandedClass,
  83. expanderCollapsedClass: options.expanderCollapsedClass
  84. });
  85. if (!options.expandAll) {
  86. target.treegrid('collapseAll');
  87. }
  88. }
  89. });
  90. }
  91. else {
  92. //也可以通过defaults里面的data属性通过传递一个数据集合进来对组件进行初始化....有兴趣可以自己实现,思路和上述类似
  93. }
  94. return target;
  95. };
  96. $.fn.treegridData.methods = {
  97. getAllNodes: function (target, data) {
  98. return target.treegrid('getAllNodes');
  99. },
  100. //组件的其他方法也可以进行类似封装........
  101. };
  102. $.fn.treegridData.defaults = {
  103. id: 'Id',
  104. parentColumn: 'ParentId',
  105. data: [], //构造table的数据集合
  106. type: "GET", //请求数据的ajax类型
  107. url: null, //请求数据的ajax的url
  108. ajaxParams: {}, //请求数据的ajax的data属性
  109. expandColumn: null,//在哪一列上面显示展开按钮
  110. expandAll: true, //是否全部展开
  111. striped: false, //是否各行渐变色
  112. bordered: false, //是否显示边框
  113. columns: [],
  114. expanderExpandedClass: 'glyphicon glyphicon-chevron-down',//展开的按钮的图标
  115. expanderCollapsedClass: 'glyphicon glyphicon-chevron-right'//缩起的按钮的图标
  116. };
  117. })(jQuery);

复制代码

代码说明

1、为了避免和源组件的初始化冲突,我们自定义的组件取了一个别名,叫 treegridData 。我们使用组件的时候就通过treegridData来进行初始化,如果你觉得这个名称不顺眼,可以自行修改。

2、代码的封装思路基本是参考博主之前介绍组件的封装 http://www.cnblogs.com/landeanfen/p/5124542.html这一篇里面的内容来的。

3、defaults里面就是初始化组件的时候可以传递的参数,上述注释基本上写得比较清楚。id和parentId两个参数主要是用来描述数据之间的父子级关系,后面我们介绍组件时候的时候你一看就能明白。

4、博主加了几个自认为很有用的属性和方法,应该能减少一些使用的麻烦。比如初始化组件的时候是否展开所有的子节点、添加title、表格行的渐变色和表格边框等。

5、上述封装里面递归查找子节点的时候,每一次都需要遍历所有的数据去找子节点,效率偏低,如果你使用了类似linq to js之类的组件去操作js的集合,可以优化那部分代码,适当提高递归的效率。当然,如果你的结果集本身数据量不太大,这么写影响也不太大。

回到顶部

3、封装后的组件使用

我们在界面上面引用需要的css和js文件

复制代码

  1.    <link href="~/Content/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
  2. <link href="~/Content/jquery-treegrid-master/css/jquery.treegrid.css" rel="stylesheet" />
  3.    <script src="~/Scripts/jquery-1.10.2.min.js"></script>
  4. <script src="~/Content/bootstrap/js/bootstrap.min.js"></script>
  5. <script src="~/Content/jquery-treegrid-master/js/jquery.treegrid.min.js"></script>
  6. <script src="~/Content/jquery-treegrid-master/js/jquery.treegrid.bootstrap3.js"></script>
  7. <script src="~/Content/jquery-treegrid-master/extension/jquery.treegrid.extension.js"></script>

复制代码

然后定义一个空的table标签

  1. <table id="tb" ></table>

最后就是js初始化了

复制代码

  1. $(document).ready(function () {
  2. $('#tb').treegridData({
  3. id: 'Id',
  4. parentColumn: 'ParentId',
  5. type: "GET", //请求数据的ajax类型
  6. url: '/TestMVC/GetData', //请求数据的ajax的url
  7. ajaxParams: {}, //请求数据的ajax的data属性
  8. expandColumn: null,//在哪一列上面显示展开按钮
  9. striped: true, //是否各行渐变色
  10. bordered: true, //是否显示边框
  11. //expandAll: false, //是否全部展开
  12. columns: [
  13. {
  14. title: '机构名称',
  15. field: 'Name'
  16. },
  17. {
  18. title: '机构描述',
  19. field: 'Desc'
  20. }
  21. ]
  22. });
  23. });

复制代码

当然啦,还得配上后台的取数据的方法

复制代码

  1.   public class TestMVCController : Controller
  2. {
  3. public JsonResult GetData()
  4. {
  5. var result = new List<object>();
  6. result.Add(new { Id = 1, Name = "百度科技", Desc = "搜索巨头"});
  7. result.Add(new { Id = 2, Name = "百度事业部", Desc = "搜索巨头",ParentId=1 });
  8. result.Add(new { Id = 3, Name = "百度人事部", Desc = "搜索巨头", ParentId = 1 });
  9. result.Add(new { Id = 11, Name = "百度HH部", Desc = "搜索巨头", ParentId = 2 });
  10. result.Add(new { Id = 4, Name = "百度行政", Desc = "搜索巨头", ParentId = 1 });
  11. result.Add(new { Id = 5, Name = "百度YY部", Desc = "搜索巨头", ParentId = 1 });
  12. result.Add(new { Id = 12, Name = "百度BB部", Desc = "搜索巨头", ParentId = 2 });
  13. result.Add(new { Id = 6, Name = "搜狐科技", Desc = "IT" });
  14. result.Add(new { Id = 7, Name = "搜狐信息部", Desc = "IT", ParentId = 6 });
  15. result.Add(new { Id = 8, Name = "搜狐人事", Desc = "IT", ParentId = 6 });
  16. result.Add(new { Id = 9, Name = "搜狐事业部", Desc = "IT", ParentId = 6 });
  17. result.Add(new { Id = 10, Name = "搜狐事业子部", Desc = "IT", ParentId = 9 });
  18. return Json(result, JsonRequestBehavior.AllowGet);
  19. }
  20. }

复制代码

这里一看应该就能明白组件defaults里面的id和parentColumn的作用了吧。记得jqgrid里面使用treeview的时候用到了一个level用来判断是哪一级别的节点,博主觉得这样硬性要求返回数据里面加一个level属性有点不妥,所以我们约定如果当前记录的parentId为null或者空字符串的时候,这个节点就是根节点,然后根据根节点去递归找子节点。

使用后的各种效果示例如下。

初始化的时候配置expandAll: false得到的效果

459756-20170427210829912-2091224638.png

增加隔行变色striped: true

459756-20170427210933490-1415573245.png

增加表格边框bordered: true

459756-20170427211029178-385948100.png

综合效果

459756-20170427211218084-1274640674.png

发表评论

表情:
评论列表 (有 0 条评论,308人围观)

还没有评论,来说两句吧...

相关阅读