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

2024-04-21 08:48

本文主要是介绍JS组件系列——自己动手封装bootstrap-treegrid组件,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

阅读目录

  • 一、开源的treegrid
    • 1、组件效果预览
    • 2、组件开源地址
  • 二、封装treegrid
    • 1、组件封装的必要性
    • 2、组件封装代码示例
    • 3、封装后的组件使用

  • 三、总结

正文

前言:最近产品需要设计一套相对完整的组织架构的解决方案,由于组织架构涉及到层级关系,在表格里面展示层级关系,自然就要用到所谓的treegrid。可惜的是,一些轻量级的表格组件本身并没有自带树形表格的功能,比如bootstrapTable就没有这个功能,怎么办呢?如果是jqgrid、easyUI的表格,treegrid的效果可以说是轻而易举就能解决,而项目目前用的就是bootstrapTable,不可能这个时候因为这个需求去换组件吧。博主分析了下,无非就两种解决方案:一种就是扩展bootstrapTable的treegrid功能;第二种就是再找一个单独的treegrid组件去实现这个功能。博主在网上找了下,找到了一个效果还不错的treegrid第三方组件,于是做了下封装,今天分享出来,供大家参考。

本文原创地址:http://www.cnblogs.com/landeanfen/p/6776152.html


一、开源的treegrid


1、组件效果预览



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的文件。



然后就是最重要的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的urlajaxParams: {}, //请求数据的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的集合,可以优化那部分代码,适当提高递归的效率。当然,如果你的结果集本身数据量不太大,这么写影响也不太大。

3、封装后的组件使用

我们在界面上面引用需要的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的urlajaxParams: {}, //请求数据的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/

欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利


发现个小bug,如下图:


原因是 treegrid-{id},冲突了。

改了改代码如下:
line 77
$.each(rootNode,  function  (i, item) {
     var  tr = $( '<tr></tr>' );
     tr.addClass( 'treegrid-'  + (++j));
     $.each(options.columns,  function  (index, column) {
         var  td = $( '<td></td>' );
         if  (column.formatter !=  null  && column.formatter != undefined) {
             td.html(column.formatter(item[column.field]));
         else  {
             td.html(item[column.field]);
         }
         tr.append(td);
     });
     tbody.append(tr);
     target.getChildNodes(data, item, j, tbody);
});

line 27
$.each(data,  function  (i, item) {
     if  (item[options.parentColumn] == parentNode[options.id]) {
         var  tr = $( '<tr></tr>' );
         tr.addClass( 'treegrid-'  + (++j));
         tr.addClass( 'treegrid-parent-'  + parentIndex);
         $.each(options.columns,  function  (index, column) {
             var  td = $( '<td></td>' );
             if  (column.formatter !=  null  && column.formatter != undefined) {
                 td.html(column.formatter(item[column.field]));
             else  {
                 td.html(item[column.field]);
             }
             tr.append(td);
         });
         tbody.append(tr);
         target.getChildNodes(data, item, j, tbody)
     }
});



这篇关于JS组件系列——自己动手封装bootstrap-treegrid组件的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/922660

相关文章

前端原生js实现拖拽排课效果实例

《前端原生js实现拖拽排课效果实例》:本文主要介绍如何实现一个简单的课程表拖拽功能,通过HTML、CSS和JavaScript的配合,我们实现了课程项的拖拽、放置和显示功能,文中通过实例代码介绍的... 目录1. 效果展示2. 效果分析2.1 关键点2.2 实现方法3. 代码实现3.1 html部分3.2

JS 实现复制到剪贴板的几种方式小结

《JS实现复制到剪贴板的几种方式小结》本文主要介绍了JS实现复制到剪贴板的几种方式小结,包括ClipboardAPI和document.execCommand这两种方法,具有一定的参考价值,感兴趣的... 目录一、Clipboard API相关属性方法二、document.execCommand优点:缺点:

C++实现封装的顺序表的操作与实践

《C++实现封装的顺序表的操作与实践》在程序设计中,顺序表是一种常见的线性数据结构,通常用于存储具有固定顺序的元素,与链表不同,顺序表中的元素是连续存储的,因此访问速度较快,但插入和删除操作的效率可能... 目录一、顺序表的基本概念二、顺序表类的设计1. 顺序表类的成员变量2. 构造函数和析构函数三、顺序表

Go语言利用泛型封装常见的Map操作

《Go语言利用泛型封装常见的Map操作》Go语言在1.18版本中引入了泛型,这是Go语言发展的一个重要里程碑,它极大地增强了语言的表达能力和灵活性,本文将通过泛型实现封装常见的Map操作,感... 目录什么是泛型泛型解决了什么问题Go泛型基于泛型的常见Map操作代码合集总结什么是泛型泛型是一种编程范式,允

四种Flutter子页面向父组件传递数据的方法介绍

《四种Flutter子页面向父组件传递数据的方法介绍》在Flutter中,如果父组件需要调用子组件的方法,可以通过常用的四种方式实现,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录方法 1:使用 GlobalKey 和 State 调用子组件方法方法 2:通过回调函数(Callb

Vue项目中Element UI组件未注册的问题原因及解决方法

《Vue项目中ElementUI组件未注册的问题原因及解决方法》在Vue项目中使用ElementUI组件库时,开发者可能会遇到一些常见问题,例如组件未正确注册导致的警告或错误,本文将详细探讨这些问题... 目录引言一、问题背景1.1 错误信息分析1.2 问题原因二、解决方法2.1 全局引入 Element

vue解决子组件样式覆盖问题scoped deep

《vue解决子组件样式覆盖问题scopeddeep》文章主要介绍了在Vue项目中处理全局样式和局部样式的方法,包括使用scoped属性和深度选择器(/deep/)来覆盖子组件的样式,作者建议所有组件... 目录前言scoped分析deep分析使用总结所有组件必须加scoped父组件覆盖子组件使用deep前言

基于Qt Qml实现时间轴组件

《基于QtQml实现时间轴组件》时间轴组件是现代用户界面中常见的元素,用于按时间顺序展示事件,本文主要为大家详细介绍了如何使用Qml实现一个简单的时间轴组件,需要的可以参考下... 目录写在前面效果图组件概述实现细节1. 组件结构2. 属性定义3. 数据模型4. 事件项的添加和排序5. 事件项的渲染如何使用

Node.js 中 http 模块的深度剖析与实战应用小结

《Node.js中http模块的深度剖析与实战应用小结》本文详细介绍了Node.js中的http模块,从创建HTTP服务器、处理请求与响应,到获取请求参数,每个环节都通过代码示例进行解析,旨在帮... 目录Node.js 中 http 模块的深度剖析与实战应用一、引言二、创建 HTTP 服务器:基石搭建(一

使用Vue.js报错:ReferenceError: “Vue is not defined“ 的原因与解决方案

《使用Vue.js报错:ReferenceError:“Vueisnotdefined“的原因与解决方案》在前端开发中,ReferenceError:Vueisnotdefined是一个常见... 目录一、错误描述二、错误成因分析三、解决方案1. 检查 vue.js 的引入方式2. 验证 npm 安装3.