JS組件系列——本身動手封裝bootstrap-treegrid組件

前言:最近產品須要設計一套相對完整的組織架構的解決方案,因爲組織架構涉及到層級關係,在表格裏面展現層級關係,天然就要用到所謂的treegrid。惋惜的是,一些輕量級的表格組件自己並無自帶樹形表格的功能,好比bootstrapTable就沒有這個功能,怎麼辦呢?若是是jqgrid、easyUI的表格,treegrid的效果能夠說是垂手可得就能解決,而項目目前用的就是bootstrapTable,不可能這個時候由於這個需求去換組件吧。博主分析了下,無非就兩種解決方案:一種就是擴展bootstrapTable的treegrid功能;第二種就是再找一個單獨的treegrid組件去實現這個功能。博主在網上找了下,找到了一個效果還不錯的treegrid第三方組件,因而作了下封裝,今天分享出來,供你們參考。css

本文原創地址:http://www.cnblogs.com/landeanfen/p/6776152.htmlhtml

1、開源的treegrid

一、組件效果預覽

最原始的效果前端

 

bootstrap樣式的效果jquery

 

這個是組件最原始的效果,後面會告訴你們博主作了哪些封裝以及加了哪些功能。git

在此仍是給出一個封裝過的效果吧!github

二、組件開源地址

最後仍是給出github上面一個開源的treegrid組件。ajax

github開源地址:https://github.com/maxazan/jquery-treegridbootstrap

文檔示例地址:http://maxazan.github.io/jquery-treegrid/架構

bootstrap樣式的demo以及使用:http://maxazan.github.io/jquery-treegrid/examples/example-bootstrap-3.htmlapp

2、封裝treegrid

一、組件封裝的必要性

(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 = $('<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);

代碼說明

一、爲了不和源組件的初始化衝突,咱們自定義的組件取了一個別名,叫 treegridData 。咱們使用組件的時候就經過treegridData來進行初始化,若是你以爲這個名稱不順眼,能夠自行修改。

二、代碼的封裝思路基本是參考博主以前介紹組件的封裝 http://www.cnblogs.com/landeanfen/p/5124542.html這一篇裏面的內容來的。

三、defaults裏面就是初始化組件的時候能夠傳遞的參數,上述註釋基本上寫得比較清楚。id和parentId兩個參數主要是用來描述數據之間的父子級關係,後面咱們介紹組件時候的時候你一看就能明白。

四、博主加了幾個自認爲頗有用的屬性和方法,應該能減小一些使用的麻煩。好比初始化組件的時候是否展開全部的子節點、添加title、表格行的漸變色和表格邊框等。

五、上述封裝裏面遞歸查找子節點的時候,每一次都須要遍歷全部的數據去找子節點,效率偏低,若是你使用了相似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

綜合效果

3、總結

至此本文就結束了,沒有什麼過高大上的技術,就是簡單將一個第三方組件進行了一些封裝,使得其使用起來更加方便而已。若是你項目中也正在爲treegrid而糾結,何不試試呢。其實擴展bootstrapTable的treegrid功能的思路博主已經有了,等有時間在下篇給出說明。

若是你以爲本文可以幫助你,能夠右邊隨意 打賞 博主,也能夠 推薦 進行精神鼓勵。你的支持是博主繼續堅持的不懈動力。

本文原創出處:http://www.cnblogs.com/landeanfen/

歡迎各位轉載,可是未經做者本人贊成,轉載文章以後必須在文章頁面明顯位置給出做者和原文鏈接,不然保留追究法律責任的權利

相關文章
相關標籤/搜索