经典树结构——自己动手封装bootstrap-treegrid组件

正文

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

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

回到顶部

一、开源的treegrid

回到顶部

1、组件效果预览

最原始的效果

bootstrap样式的效果

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

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

回到顶部

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的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的集合,可以优化那部分代码,适当提高递归的效率。当然,如果你的结果集本身数据量不太大,这么写影响也不太大。

回到顶部

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的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/

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

原文地址:https://www.cnblogs.com/TigerZhang-home/p/8185074.html

时间: 2024-08-28 15:32:03

经典树结构——自己动手封装bootstrap-treegrid组件的相关文章

JS组件系列——分享自己封装的Bootstrap树形组件:jqTree

前言:之前的一篇介绍了下如何封装自己的组件,这篇再次来体验下自己封装组件的乐趣.看过博主博客的园友应该记得之前分享过一篇树形菜单的使用JS组件系列——Bootstrap 树控件使用经验分享,这篇里面第一个Jquery Tree,只是用简单样式和js去实现了效果,没有给出一个系统的封装,这篇博主就来试试在此样式的基础上封装一个稍微完整点的树形组件. 一.组件效果预览 其实效果和之前的那个差不多,博主只是在之前的基础上加了一个选中的背景色. 全部收起 展开 全部展开 二.代码示例 其实效果很简单,重

源码时代前端干货分享|从零动手封装一个通用的vue按钮组件

我们在使用目前最主流的前端框架vue在开发过程中,组件是一个非常重要的组成部分,可以这么说,所有的vue 应用,都是由一个一个的小组件拼装而成的.正是由于vue组件如此重要,所以vue的生态中,也非常多的UI组件库,其中最著名的非Element-UI莫属,里面有非常多的封装完善的组件提供给我们使用,大大的增强了我们的开发效率.那么,这些UI框架的组件,究竟是如何封装的呢?如何动手从零开始封装自己的组件呢?接下来,我们就从最简单的一个Button的组件封装说起.如下,是Element-UI中的按钮

angularjs封装bootstrap官网的时间插件datetimepicker

背景:angular与jquery类库的协作 第三方类库中,不得不提的是大名鼎鼎的jquery,现在基本上已经是国内web开发的必修工具了.它灵活的dom操作,让很多web开发人员欲罢不能.再加上已经很成熟的jquery UI 库和大量jquery 插件,几乎是一个取之不尽用之不竭的宝库.然而,它是否能与angularjs结合呢? 很多angularjs原教旨主义者对此持否定态度.他们认为,既然已经使用了angularjs做web应用框架,那就必须避免其他类库的干扰,做纯净的MvvM模式应用.任

JS组件系列——两种bootstrap multiselect组件大比拼

原文:http://www.cnblogs.com/landeanfen/p/5013452.html 前言:今天继续来看看bootstrap的另一个组件:multiselect.记得在项目开始之前,博主项目组几个同事就使用哪些js组件展开过讨论,其中就说到了select组件,由于项目的整体风格使用的bootstrap风格,所以在选用select组件的时候优先考虑和bootstrap结合使用的.其中就找到了两个这种组件,大体样式和功能基本相同,经过一番讨论,项目组决定使用davidstutz的b

bootstrap Typeahead组件

使用 Bootstrap Typeahead 组件 Bootstrap 中的 Typeahead 组件就是通常所说的自动完成 AutoComplete,功能很强大,但是,使用上并不太方便.这里我们将介绍一下这个组件的使用. 第一,简单使用 首先,最简单的使用方式,就是直接在标记中声明,通过 data-provide="typeahead" 来声明这是一个 typeahead 组件,通过 data-source= 来提供数据.当然了,你还必须提供 bootstrap-typeahead.

Bootstrap 布局组件

Bootstrap 布局组件 1.Bootstrap字体图标 (1).字体图标列表链接 http://www.runoob.com/bootstrap/bootstrap-glyphicons.html (2).用法 如需使用图标,只需要简单地使用下面的代码即可.请在图标和文本之间保留适当的空间.没有glyphicon的css. <span class="glyphicon glyphicon-search"></span> (3).定制字体图标 我们已经看到如

基于jQuery的TreeGrid组件详解

一.TreeGrid组件相关的类 1.TreeGrid(_config) _config:json格式的数据,组件所需要的数据都通过该参数提供. 2.TreeGridItem(_root, _rowId, _rowIndex, _rowData) _root:显示组件实例的目标容器对象. _rowId:选中行的id. _rowIndex:选中行的索引. _rowData:json格式的行数据. 二._config参数详解 id:组件实例的id. width:组件实例的宽度. renderTo:用

JS组件系列——Bootstrap Select2组件使用小结

前言:在介绍select组件的时候,博主之前分享过一篇JS组件系列——两种bootstrap multiselect组件大比拼,这两个组件的功能确实很强大,只可惜没有图文结合的效果(也就是将图片放入到select里面随着文字一起显示).前两天做一个菜单图标选择的功能,就要用到这个图文选择的功能.于是乎又是找啊找.终于不负所望,找到了我们伟大的select2组件.今天分享下这个组件的一些用法和特性. 一.组件说明以及API说明 Select2使用示例地址:https://select2.githu

easyUI中treegrid组件构造树形表格(简单数据类型)+ssm后台

这几天做的项目要求用树形表格的形式展示一部分数据,于是就想到了使用easyUI的treegrid组件,但几经翻查各种资料,发现数据类型大多采取标准数据类型,即包含children元素的数据类型,小编查遍各种资料,几经实验,小编找到了一种使用简单数据类型的展示树形表格的方法.在这里介绍给大家,仅供参考: 框架使用的是ssm框架,数据库用的是oracle,其中数据库中要展示的表设计成大致如下的样子: 参考了一下easyUI的demo中给出的数据类型,如下格式: 打开里面显示如下: 这是一个json串