新上手一個項目, 於是正好想學習下bootstrap, 因此就採用asp.net mvc + bootstrap來作. 由於須要TreeGrid的控件, 原本想用easyUI、LingerUi、DWZ, 但顯示效果總以爲不協調. 搜來搜去, 發現了牛人寫的 jquery-treegrid, 因此就參考這園子裏的兩篇文章開始作:javascript
JS組件系列——本身動手封裝bootstrap-treegrid組件: http://www.cnblogs.com/landeanfen/p/6776152.htmlcss
JS組件系列——封裝本身的JS組件,你也能夠: http://www.cnblogs.com/landeanfen/p/5124542.htmlhtml
此次目的是擴展jquery-treegrid插件, 實現checkbox的全選、單選, 也照着上文添加了ajax遠程獲取數據的功能. 雖而後來發現了Kendo UI, 但本着學習的目的, 仍是完成了此次的插件擴展功能.前端
因爲常年沒有接觸過前端, 因此jquery基本語法都磕磕絆絆更別說擴展插件了, 邊摸索邊作. 待我改完一版本, 才能理解了jquery-treegrid插件的做者真的牛掰:java
1. jquery-treegrid思想: 沒有硬編碼的html, 所有經過css樣式實現. 像樹形結點的維護、結點的打開與摺疊狀態, 都是由寫在TR元素上的css來實現. 也卻是jquery自己不熟吧, 我第一次見這麼少的html來實現的jQuery控件.node
2. 插件的結構: 跟上面的整體結構相似, 都是 method{}方法集合、$.fn.treegrid擴展、default{}默認參數對象. 其經過初始化函數initTree來開始渲染table元素, 經過保存控件容器(TreeContainer) -> 保存全局設置(Settings) -> 遞歸地初始化結點(initNode) -> 爲每一個結點添加事件(intExpander、initIdent、initEvents、initState、initChangeEvent、initSettingsEvents)來完成最終功能. 總體上有點面向對象的意味, 跟以前本身寫的JS差距甚大.jquery
剛開始我也是照着前面兩篇的文章來實現了基本的樣子, 當我快作完的時候才理解了jquery-treegrid控件做者的思路. 根據前兩篇文章的思路, 就是在初始化方法中, 經過ajax獲取數據, 而後在回調方法中拼接HTML表格, 來完成對jquery-treegrid的遠程取數據的擴展. 當我基本理解了jQuery-treegrid做者的思想之後, 嘗試將上面的代碼改爲: 在獲取遠程數據後, render表格(renderHeader、RenderBody、遞歸的生成List類型的Tr和Tree類型的Tr)、以後初始化Header(初始化checkAll、DelAll、操做列)、再日後初始化結點(initExpander、initIndent、initCheck、initOperation、initEvnets、initState、initChangeEvent、initSettingsEvents). 全部操做(如:全選、所有選、直選部分)等操做, 也都是經過在Tr元素上附加css來實現的.git
總結實現過程的砍兒:github
1. 理解插件開發思路及手段, 爲何採用如此結構來組織插件.ajax
2. 控件狀態的處理實際上是使用了cookie, 用jquery-cookie來實現的.
3. 特別要理解This所表明的對象, 能夠在調試界面一步步驗證this所表明的對象.
4. 關於原jquery-treegrid插件的封裝, $(this).原控件('方法名','參數')來封裝. 這裏須要注意的是: 在咱們本身的擴展代碼中, 關於狀態保存、容器位置、設置保存等內容, 我都是經過對原控件的封裝, 將這些數據寫在同一個位置, 以便實現咱們本身的控件和原控件之間的數據共享.
5. 默認default對象之中的方法的調用: 1. 經過settings.方法名.apply(this, '參數')來調用. 2. 經過咱們擴展控件中封裝的, $(this).treegridExt('getSetting','方法名').apply(this,'參數')來實現的.
6. 注意參數的問題: 有時用this、有時用$(this)、有時用$($(this).treegridExt('方法名'))、有使用[$(this)], 有時用apply(this)、還有時用apply($(Elem))等等. 決定使用哪一種方式的的根本緣由就是 this所表明的當前對象. 根據當前對象的不一樣, 來變換幾種參數形式.
最後, 廢話很少說, 上代碼. 注意: 改代碼只實現了全選、全不選、選子項、以及子項變動後對父級選項的調整. 以後沒有再深刻編碼, 由於項目仍是比較緊, 考慮一個個控件本身搞仍是太費勁了, 準備採用Kendo控件來完成項目, 此Demo僅做爲學習jquery和擴展其插件的相關知識爲目的. 順帶對老大說聲抱歉, 多耽誤2,3天(算上端午的話多是5天).
//jquery.treegrid.js
/* * jQuery treegrid Plugin 0.3.0 * https://github.com/maxazan/jquery-treegrid * * Copyright 2013, Pomazan Max * Licensed under the MIT licenses. */ (function($) { var methods = { /** * Initialize tree * * @param {Object} options * @returns {Object[]} */ initTree: function(options) { var settings = $.extend({}, this.treegrid.defaults, options); return this.each(function() { var $this = $(this); $this.treegrid('setTreeContainer', $(this)); $this.treegrid('setSettings', settings); settings.getRootNodes.apply(this, [$(this)]).treegrid('initNode', settings); $this.treegrid('getRootNodes').treegrid('render'); }); }, /** * Initialize node * * @param {Object} settings * @returns {Object[]} */ initNode: function(settings) { return this.each(function() { var $this = $(this); $this.treegrid('setTreeContainer', settings.getTreeGridContainer.apply(this)); $this.treegrid('getChildNodes').treegrid('initNode', settings); $this.treegrid('initExpander').treegrid('initIndent').treegrid('initEvents').treegrid('initState').treegrid('initChangeEvent').treegrid("initSettingsEvents"); }); }, initChangeEvent: function() { var $this = $(this); //Save state on change $this.on("change", function() { var $this = $(this); $this.treegrid('render'); if ($this.treegrid('getSetting', 'saveState')) { $this.treegrid('saveState'); } }); return $this; }, /** * Initialize node events * * @returns {Node} */ initEvents: function() { var $this = $(this); //Default behavior on collapse $this.on("collapse", function() { var $this = $(this); $this.removeClass('treegrid-expanded'); $this.addClass('treegrid-collapsed'); }); //Default behavior on expand $this.on("expand", function() { var $this = $(this); $this.removeClass('treegrid-collapsed'); $this.addClass('treegrid-expanded'); }); return $this; }, /** * Initialize events from settings * * @returns {Node} */ initSettingsEvents: function() { var $this = $(this); //Save state on change $this.on("change", function() { var $this = $(this); if (typeof($this.treegrid('getSetting', 'onChange')) === "function") { $this.treegrid('getSetting', 'onChange').apply($this); } }); //Default behavior on collapse $this.on("collapse", function() { var $this = $(this); if (typeof($this.treegrid('getSetting', 'onCollapse')) === "function") { $this.treegrid('getSetting', 'onCollapse').apply($this); } }); //Default behavior on expand $this.on("expand", function() { var $this = $(this); if (typeof($this.treegrid('getSetting', 'onExpand')) === "function") { $this.treegrid('getSetting', 'onExpand').apply($this); } }); return $this; }, /** * Initialize expander for node * * @returns {Node} */ initExpander: function() { var $this = $(this); var cell = $this.find('td').get($this.treegrid('getSetting', 'treeColumn')); var tpl = $this.treegrid('getSetting', 'expanderTemplate'); var expander = $this.treegrid('getSetting', 'getExpander').apply(this); if (expander) { expander.remove(); } $(tpl).prependTo(cell).click(function() { $($(this).closest('tr')).treegrid('toggle'); }); return $this; }, /** * Initialize indent for node * * @returns {Node} */ initIndent: function() { var $this = $(this); $this.find('.treegrid-indent').remove(); var tpl = $this.treegrid('getSetting', 'indentTemplate'); var expander = $this.find('.treegrid-expander'); var depth = $this.treegrid('getDepth'); for (var i = 0; i < depth; i++) { $(tpl).insertBefore(expander); } return $this; }, /** * Initialise state of node * * @returns {Node} */ initState: function() { var $this = $(this); if ($this.treegrid('getSetting', 'saveState') && !$this.treegrid('isFirstInit')) { $this.treegrid('restoreState'); } else { if ($this.treegrid('getSetting', 'initialState') === "expanded") { $this.treegrid('expand'); } else { $this.treegrid('collapse'); } } return $this; }, /** * Return true if this tree was never been initialised * * @returns {Boolean} */ isFirstInit: function() { var tree = $(this).treegrid('getTreeContainer'); if (tree.data('first_init') === undefined) { tree.data('first_init', $.cookie(tree.treegrid('getSetting', 'saveStateName')) === undefined); } return tree.data('first_init'); }, /** * Save state of current node * * @returns {Node} */ saveState: function() { var $this = $(this); if ($this.treegrid('getSetting', 'saveStateMethod') === 'cookie') { var stateArrayString = $.cookie($this.treegrid('getSetting', 'saveStateName')) || ''; var stateArray = (stateArrayString === '' ? [] : stateArrayString.split(',')); var nodeId = $this.treegrid('getNodeId'); if ($this.treegrid('isExpanded')) { if ($.inArray(nodeId, stateArray) === -1) { stateArray.push(nodeId); } } else if ($this.treegrid('isCollapsed')) { if ($.inArray(nodeId, stateArray) !== -1) { stateArray.splice($.inArray(nodeId, stateArray), 1); } } $.cookie($this.treegrid('getSetting', 'saveStateName'), stateArray.join(',')); } return $this; }, /** * Restore state of current node. * * @returns {Node} */ restoreState: function() { var $this = $(this); if ($this.treegrid('getSetting', 'saveStateMethod') === 'cookie') { var stateArray = $.cookie($this.treegrid('getSetting', 'saveStateName')).split(','); if ($.inArray($this.treegrid('getNodeId'), stateArray) !== -1) { $this.treegrid('expand'); } else { $this.treegrid('collapse'); } } return $this; }, /** * Method return setting by name * * @param {type} name * @returns {unresolved} */ getSetting: function(name) { if (!$(this).treegrid('getTreeContainer')) { return null; } return $(this).treegrid('getTreeContainer').data('settings')[name]; }, /** * Add new settings * * @param {Object} settings */ setSettings: function(settings) { $(this).treegrid('getTreeContainer').data('settings', settings); }, /** * Return tree container * * @returns {HtmlElement} */ getTreeContainer: function() { return $(this).data('treegrid'); }, /** * Set tree container * * @param {HtmlE;ement} container */ setTreeContainer: function(container) { return $(this).data('treegrid', container); }, /** * Method return all root nodes of tree. * * Start init all child nodes from it. * * @returns {Array} */ getRootNodes: function () { return $(this).treegrid('getSetting', 'getRootNodes').apply(this, [$(this).treegrid('getTreeContainer')]); }, /** * Method return all nodes of tree. * * @returns {Array} */ getAllNodes: function() { return $(this).treegrid('getSetting', 'getAllNodes').apply(this, [$(this).treegrid('getTreeContainer')]); }, /** * Mthod return true if element is Node * * @returns {String} */ isNode: function() { return $(this).treegrid('getNodeId') !== null; }, /** * Mthod return id of node * * @returns {String} */ getNodeId: function() { if ($(this).treegrid('getSetting', 'getNodeId') === null) { return null; } else { return $(this).treegrid('getSetting', 'getNodeId').apply(this); } }, /** * Method return parent id of node or null if root node * * @returns {String} */ getParentNodeId: function() { return $(this).treegrid('getSetting', 'getParentNodeId').apply(this); }, /** * Method return parent node or null if root node * * @returns {Object[]} */ getParentNode: function() { if ($(this).treegrid('getParentNodeId') === null) { return null; } else { return $(this).treegrid('getSetting', 'getNodeById').apply(this, [$(this).treegrid('getParentNodeId'), $(this).treegrid('getTreeContainer')]); } }, /** * Method return array of child nodes or null if node is leaf * * @returns {Object[]} */ getChildNodes: function() { return $(this).treegrid('getSetting', 'getChildNodes').apply(this, [$(this).treegrid('getNodeId'), $(this).treegrid('getTreeContainer')]); }, /** * Method return depth of tree. * * This method is needs for calculate indent * * @returns {Number} */ getDepth: function() { if ($(this).treegrid('getParentNode') === null) { return 0; } return $(this).treegrid('getParentNode').treegrid('getDepth') + 1; }, /** * Method return true if node is root * * @returns {Boolean} */ isRoot: function() { return $(this).treegrid('getDepth') === 0; }, /** * Method return true if node has no child nodes * * @returns {Boolean} */ isLeaf: function() { return $(this).treegrid('getChildNodes').length === 0; }, /** * Method return true if node last in branch * * @returns {Boolean} */ isLast: function() { if ($(this).treegrid('isNode')) { var parentNode = $(this).treegrid('getParentNode'); if (parentNode === null) { if ($(this).treegrid('getNodeId') === $(this).treegrid('getRootNodes').last().treegrid('getNodeId')) { return true; } } else { if ($(this).treegrid('getNodeId') === parentNode.treegrid('getChildNodes').last().treegrid('getNodeId')) { return true; } } } return false; }, /** * Method return true if node first in branch * * @returns {Boolean} */ isFirst: function() { if ($(this).treegrid('isNode')) { var parentNode = $(this).treegrid('getParentNode'); if (parentNode === null) { if ($(this).treegrid('getNodeId') === $(this).treegrid('getRootNodes').first().treegrid('getNodeId')) { return true; } } else { if ($(this).treegrid('getNodeId') === parentNode.treegrid('getChildNodes').first().treegrid('getNodeId')) { return true; } } } return false; }, /** * Return true if node expanded * * @returns {Boolean} */ isExpanded: function() { return $(this).hasClass('treegrid-expanded'); }, /** * Return true if node collapsed * * @returns {Boolean} */ isCollapsed: function() { return $(this).hasClass('treegrid-collapsed'); }, /** * Return true if at least one of parent node is collapsed * * @returns {Boolean} */ isOneOfParentsCollapsed: function() { var $this = $(this); if ($this.treegrid('isRoot')) { return false; } else { if ($this.treegrid('getParentNode').treegrid('isCollapsed')) { return true; } else { return $this.treegrid('getParentNode').treegrid('isOneOfParentsCollapsed'); } } }, /** * Expand node * * @returns {Node} */ expand: function() { if (!this.treegrid('isLeaf') && !this.treegrid("isExpanded")) { this.trigger("expand"); this.trigger("change"); return this; } return this; }, /** * Expand all nodes * * @returns {Node} */ expandAll: function() { var $this = $(this); $this.treegrid('getRootNodes').treegrid('expandRecursive'); return $this; }, /** * Expand current node and all child nodes begin from current * * @returns {Node} */ expandRecursive: function() { return $(this).each(function() { var $this = $(this); $this.treegrid('expand'); if (!$this.treegrid('isLeaf')) { $this.treegrid('getChildNodes').treegrid('expandRecursive'); } }); }, /** * Collapse node * * @returns {Node} */ collapse: function() { return $(this).each(function() { var $this = $(this); if (!$this.treegrid('isLeaf') && !$this.treegrid("isCollapsed")) { $this.trigger("collapse"); $this.trigger("change"); } }); }, /** * Collapse all nodes * * @returns {Node} */ collapseAll: function() { var $this = $(this); $this.treegrid('getRootNodes').treegrid('collapseRecursive'); return $this; }, /** * Collapse current node and all child nodes begin from current * * @returns {Node} */ collapseRecursive: function() { return $(this).each(function() { var $this = $(this); $this.treegrid('collapse'); if (!$this.treegrid('isLeaf')) { $this.treegrid('getChildNodes').treegrid('collapseRecursive'); } }); }, /** * Expand if collapsed, Collapse if expanded * * @returns {Node} */ toggle: function() { var $this = $(this); if ($this.treegrid('isExpanded')) { $this.treegrid('collapse'); } else { $this.treegrid('expand'); } return $this; }, /** * Rendering node * * @returns {Node} */ render: function() { return $(this).each(function() { var $this = $(this); //if parent colapsed we hidden if ($this.treegrid('isOneOfParentsCollapsed')) { $this.hide(); } else { $this.show(); } if (!$this.treegrid('isLeaf')) { $this.treegrid('renderExpander'); $this.treegrid('getChildNodes').treegrid('render'); } }); }, /** * Rendering expander depends on node state * * @returns {Node} */ renderExpander: function() { return $(this).each(function() { var $this = $(this); var expander = $this.treegrid('getSetting', 'getExpander').apply(this); if (expander) { if (!$this.treegrid('isCollapsed')) { expander.removeClass($this.treegrid('getSetting', 'expanderCollapsedClass')); expander.addClass($this.treegrid('getSetting', 'expanderExpandedClass')); } else { expander.removeClass($this.treegrid('getSetting', 'expanderExpandedClass')); expander.addClass($this.treegrid('getSetting', 'expanderCollapsedClass')); } } else { $this.treegrid('initExpander'); $this.treegrid('renderExpander'); } }); } }; $.fn.treegrid = function(method) { if (methods[method]) { return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); } else if (typeof method === 'object' || !method) { return methods.initTree.apply(this, arguments); } else { $.error('Method with name ' + method + ' does not exists for jQuery.treegrid'); } }; /** * Plugin's default options */ $.fn.treegrid.defaults = { initialState: 'expanded', saveState: false, saveStateMethod: 'cookie', saveStateName: 'tree-grid-state', expanderTemplate: '<span class="treegrid-expander"></span>', indentTemplate: '<span class="treegrid-indent"></span>', expanderExpandedClass: 'treegrid-expander-expanded', expanderCollapsedClass: 'treegrid-expander-collapsed', treeColumn: 0, getExpander: function() { return $(this).find('.treegrid-expander'); }, getNodeId: function() { var template = /treegrid-([A-Za-z0-9_-]+)/; if (template.test($(this).attr('class'))) { return template.exec($(this).attr('class'))[1]; } return null; }, getParentNodeId: function() { var template = /treegrid-parent-([A-Za-z0-9_-]+)/; if (template.test($(this).attr('class'))) { return template.exec($(this).attr('class'))[1]; } return null; }, getNodeById: function(id, treegridContainer) { var templateClass = "treegrid-" + id; return treegridContainer.find('tr.' + templateClass); }, getChildNodes: function(id, treegridContainer) { var templateClass = "treegrid-parent-" + id; return treegridContainer.find('tr.' + templateClass); }, getTreeGridContainer: function() { return $(this).closest('table'); }, getRootNodes: function(treegridContainer) { var result = $.grep(treegridContainer.find('tr'), function(element) { var classNames = $(element).attr('class'); var templateClass = /treegrid-([A-Za-z0-9_-]+)/; var templateParentClass = /treegrid-parent-([A-Za-z0-9_-]+)/; return templateClass.test(classNames) && !templateParentClass.test(classNames); }); return $(result); }, getAllNodes: function(treegridContainer) { var result = $.grep(treegridContainer.find('tr'), function(element) { var classNames = $(element).attr('class'); var templateClass = /treegrid-([A-Za-z0-9_-]+)/; return templateClass.test(classNames); }); return $(result); }, //Events onCollapse: null, onExpand: null, onChange: null }; })(jQuery);
//jquery.treegrid.css
.treegrid-indent {width:16px; height: 16px; display: inline-block; position: relative;} .treegrid-expander {width:16px; height: 16px; display: inline-block; position: relative; cursor: pointer;} .treegrid-expander-expanded{background-image: url(../img/collapse.png); } .treegrid-expander-collapsed{background-image: url(../img/expand.png);}
//jquery.treegrid.bootstrap3.js
$.extend($.fn.treegrid.defaults, { expanderExpandedClass: 'glyphicon glyphicon-chevron-down', expanderCollapsedClass: 'glyphicon glyphicon-chevron-right' });
//jquey.cookie.js
/*! * jQuery Cookie Plugin v1.3.1 * https://github.com/carhartl/jquery-cookie * * Copyright 2013 Klaus Hartl * Released under the MIT license */ (function (factory) { if (typeof define === 'function' && define.amd) { // AMD. Register as anonymous module. define(['jquery'], factory); } else { // Browser globals. factory(jQuery); } }(function ($) { var pluses = /\+/g; function decode(s) { if (config.raw) { return s; } return decodeURIComponent(s.replace(pluses, ' ')); } function decodeAndParse(s) { if (s.indexOf('"') === 0) { // This is a quoted cookie as according to RFC2068, unescape... s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\'); } s = decode(s); try { return config.json ? JSON.parse(s) : s; } catch(e) {} } var config = $.cookie = function (key, value, options) { // Write if (value !== undefined) { options = $.extend({}, config.defaults, options); if (typeof options.expires === 'number') { var days = options.expires, t = options.expires = new Date(); t.setDate(t.getDate() + days); } value = config.json ? JSON.stringify(value) : String(value); return (document.cookie = [ config.raw ? key : encodeURIComponent(key), '=', config.raw ? value : encodeURIComponent(value), options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE options.path ? '; path=' + options.path : '', options.domain ? '; domain=' + options.domain : '', options.secure ? '; secure' : '' ].join('')); } // Read var cookies = document.cookie.split('; '); var result = key ? undefined : {}; for (var i = 0, l = cookies.length; i < l; i++) { var parts = cookies[i].split('='); var name = decode(parts.shift()); var cookie = parts.join('='); if (key && key === name) { result = decodeAndParse(cookie); break; } if (!key) { result[name] = decodeAndParse(cookie); } } return result; }; config.defaults = {}; $.removeCookie = function (key, options) { if ($.cookie(key) !== undefined) { // Must not alter options, thus extending a fresh object... $.cookie(key, '', $.extend({}, options, { expires: -1 })); return true; } return false; }; }));
////以上是jquery-treegrid的主要先關內容, 如下是此次擴展的代碼
//jquey.treegrid.extention.js
/* * jQuery treegrid extension 0.1.0 * * Copyright 2017, Jalen Zhang * Licensed under the MIT licenses. */ ; (function ($) { "use strict"; //嚴格模式下, 全局對象沒法使用默認綁定 /*begin private functions*/ var nodeCount = 0; //全局結點計數 //從數據中獲取跟結點 var getRootNodesFromData = function (data,isTreedData,parentCol,sortCol) { var result = []; $.each(data, function (index, item) { if (isTreedData || !item[parentCol] || item[parentCol] == 0) { result.push(item); } }); if (sortCol) { result.sort(function (a, b) { return a[sortCol] - b[sortCol]; }); } return result; } //從數據中獲取子節點 var getListChildNodesFromData = function (data, parentNode,idCol,parentCol,sortCol) { var unsort = []; $.each(data, function (i, item) { if (item[parentCol] == parentNode[idCol]) { unsort.push(item); } }); if (unsort == null || unsort.length < 1) return; if (sortCol) { unsort.sort(function (a, b) { return a[sortCol] - b[sortCol]; }); } return unsort; } var getTreeChildNodesFromdata = function (parentNode,childCol,sortCol) { if (childCol) { var childNodes = parentNode[childCol]; if (sortCol) childNodes.sort(function (a, b) { return a[sortCol] - b[sortCol]; }); return childNodes; } return null; } /*end private functions*/ /*Main*/ $.fn.treegridExt = function (method) { if (methods[method]) { //若是是調用方法(參數對象中含有方法名) return methods[method].apply(this, Array.prototype.slice.call(arguments, 1)); } else if (typeof method === 'object' || !method) { //調用初始化函數(參數不含方法名) return methods.initExtTree.apply(this, arguments); } else { $.error('Method with name ' + method + ' does not exists for jQuery.treegridExt'); return this; } }; /*public functions*/ var methods = { initExtTree: function (options) { //獲取配置信息 var settings = $.extend({}, this.treegrid.defaults, this.treegridExt.defaults, options || {}); var $this = $(this); //Code //設置控件容器 $this.treegridExt('setTreeContainer', $this); //保存設置 $this.treegridExt('setSettings', settings); if (!settings.url) { //載入數據 var data = $this.treegridExt('loadData',settings); if (data && data.length > 0) { //生成表格 $this.treegridExt('renderTable',data); } //初始化header settings.getTableHeader.apply(this,[$this]).treegridExt('initHeader',settings); //初始化結點 settings.getRootNodes.apply(this, [$this]).treegridExt('initNode', settings); //生成樹 $this.treegridExt('getRootNodes').treegridExt('render'); //默認展開狀態 if (!settings.expandAll) { $this.treegridExt('collapseAll'); } } else { $this.treegridExt('loadData',settings); } return $this; }, dispose: function (options) { return $(this).each(function () { var $this = $(this); $this.treegridExt('delState'); $this.treegridExt('delSettings'); $this.treegridExt('delTreeContainer'); }); }, val: function (options) { //獲取選擇器中第一個元素的html return this.eq(0).html(); }, //##Beigin自定義初始化方法 /*init*/ initHeader: function (settings) { return this.each(function () { var $this = $(this); $this.treegridExt('setTreeContainer', settings.getTreeGridContainer.apply(this)); $this.treegridExt('initCheckAll').treegridExt('initDelAll'); if ($this.treegridExt('getSetting', 'showOperation')) { var cell = $('<th></th>'); cell.text('操做'); $this.append(cell); } return $this; }); }, initNode: function (settings) { return this.each(function () { var $this = $(this); $this.treegridExt('setTreeContainer', settings.getTreeGridContainer.apply(this)); $this.treegridExt('initExpander').treegridExt('initIndent').treegridExt('initCheck').treegridExt('initOperation').treegridExt('initEvents').treegridExt('initState').treegridExt('initChangeEvent').treegridExt('initSettingsEvents'); $this.treegridExt('getChildNodes').treegridExt('initNode', settings); }); }, initCheckAll: function () { var $this = $(this); if ($this.treegridExt('getSetting', 'showCheck') && $this.treegridExt('getSetting', 'showCheckAll')) { $this.addClass('treegridExt-checkboxAll'); var cell = $('<th></th>'); var tpl = $this.treegridExt('getSetting', 'checkTemplate'); var checks = $this.treegridExt('getSetting', 'getCheckbox').apply(this); if (checks && checks.length > 0) { checks.remove(); } $this.prepend(cell.append(tpl)); $this.treegridExt('getSetting', 'getCheckbox').apply(this).click(function () { $this.treegridExt('toggleCheckAll'); }); } return $this; }, initDelAll: function () { var $this = $(this); if ($this.treegridExt('getSetting', 'showCheckAll') && $this.treegridExt('getSetting', 'showDelAll')) { var cell = $this.find('th').get(0); var delTpl = $this.treegridExt('getSetting', 'delAllTemplate'); var checks = $this.treegridExt('getSetting', 'getDelAll').apply(this); if (checks && checks.length > 0) { checks.remove(); } $(cell).append(delTpl); $this.treegridExt('getSetting', 'getDelAll').apply(this).click(function () { $this.treegridExt('delChecked'); }); } return $this; }, initCheck: function () { var $this = $(this); if ($this.treegridExt('getSetting', 'showCheck')) { var cell = $('<td></td>'); var tpl = $this.treegridExt('getSetting', 'checkTemplate'); var checks = $this.treegridExt('getSetting', 'getCheckbox'); if (checks && checks.length > 0) { checks.remove(); } $this.prepend(cell.append(tpl)); $this.treegridExt('getSetting', 'getCheckbox').apply(this).click(function () { $this.treegridExt('toggleCheck'); }); } return $this; }, initOperation: function () { var $this = $(this); if ($this.treegridExt('getSetting', 'showOperation')) { var cell = $('<td></td>'); var tpl = $this.treegridExt('getSetting', 'operationTemplate'); $this.append(cell.append(tpl)); } return $this; }, initEvents: function () { var $this = $(this); //Default behavior on check $this.on('check', function () { var $this = $(this); $this.addClass('treegrid-checked'); }); //Default behavior on other operations return $this.treegrid('initEvents'); }, initSettingsEvents: function () { var $this = $(this); //Save state on check $this.on('check', function () { var $this = $(this); if (typeof ($this.treegridExt('getSetting', 'onCheck')) === "function") { $this.treegridExt('getSetting', 'onCheck').apply($this); } }); //Save state on other operation return $this.treegrid('initSettingsEvents'); }, //##end自定義的初始化方法 //##Begin原組件的方法的封裝 /*init*/ initExpander: function () { return $(this).treegrid('initExpander'); }, initIndent: function () { return $(this).treegrid('initIndent'); }, initState: function () { return $(this).treegrid('initState'); }, initChangeEvent: function () { var $this = $(this); //Save state on chagne $this.on('change', function () { var $this = $(this); $this.treegridExt('render'); if ($this.treegridExt('getSetting', 'saveState')) { $this.treegridExt('saveState'); } }); return $this; }, /*init-event*/ /*base*/ getTreeContainer: function () { return $(this).treegrid('getTreeContainer'); }, setTreeContainer: function (container) { //擴展插件和原插件使用相同的存儲空間 return $(this).treegrid('setTreeContainer', container); }, getSetting: function (name) { return $(this).treegrid('getSetting',name); }, setSettings: function (settings) { return $(this).treegrid('setSettings',settings); }, restoreState: function () { return $(this).treegrid('restoreState'); }, saveState: function () { return $(this).treegrid('saveState'); }, /*node*/ getAllNodes: function () { return $(this).treegrid('getAllNodes'); }, getParentNode: function () { return $(this).treegrid('getParentNode'); }, getChildNodes: function () { return $(this).treegrid('getChildNodes'); }, /*fake-id*/ getNodeId: function () { return $(this).treegrid('getNodeId'); }, getParentNodeId: function () { return $(this).treegrid('getParentNodeId'); }, getDepth: function () { return $(this).treegrid('getDepth'); }, /*bool*/ isRoot: function () { return $(this).treegrid('isRoot'); }, isNode: function () { return $(this).treegrid('isNode'); }, isLeaf: function () { return $(this).treegrid('isLeaf'); }, isFirst: function () { return $(this).treegrid('isFirst'); }, isLast: function () { return $(this).treegrid('isLast'); }, isExpanded: function () { return $(this).treegrid('isExpanded'); }, isCollapsed: function () { return $(this).treegrid('isCollapsed'); }, isFirstInit: function () { return $(this).treegrid('isFirstInit'); }, isOneOfParentsCollapsed: function () { return $(this).treegrid('isOneOfParentsCollapsed'); }, /*verb*/ expand: function () { return $(this).treegrid('expand'); }, expandAll: function () { return $(this).treegrid('expandAll'); }, expandRecursive: function () { return $(this).treegrid('expandRecursive'); }, collapse: function () { return $(this).treegrid('collapse'); }, collapseAll: function () { return $(this).treegrid('collapseAll'); }, collapseRecursive: function () { return $(this).treegrid('collapseRecursive'); }, /* toggle: function () { return $(this).treegrid('toggle').apply(this); },*/ //##End原組件方法的封裝 //自定義的方法........ delState: function () { $.cookie($this.treegridExt('getSetting', 'saveStateName'), null); }, delSettings: function () { if (!$(this).treegridExt('getTreeContainer')) return; $this.treegridExt('getTreeContainer').removeData('settings'); }, delTreeContainer: function () { if (!$(this).treegridExt('getTreeContainer')) return; return $(this).removeData('treegrid', container); }, check: function (isCheck) { var $this = $(this); if (isCheck) { $this.treegridExt('getSetting', 'getCheckbox').apply(this).prop('checked',true); $this.addClass('treegridExt-checked'); if ($this.treegrid('isCollapsed')) { $this.treegrid('expand'); } } else { $this.treegridExt('getSetting', 'getCheckbox').apply(this).prop('checked', false); $this.removeClass('treegridExt-checked'); } return $this; }, checkDownRecursive: function (isCheck) { //return $(this).each(function () { var $this = $(this); $this.treegridExt('check', isCheck); if (!$this.treegridExt('isLeaf')) { $this.treegridExt('getChildNodes').treegridExt('checkDownRecursive', isCheck); } return $this; //}); }, checkUpRecursive: function (isCheck) { var parentNode = $(this).treegridExt('getParentNode'); if (parentNode) { var tag = true; $.each(parentNode.treegridExt('getChildNodes'), function () { var $this = $(this); //異或: T^T(false)、T^F(true)、F^T(true)、F^F(false), 全選或全不選(true), 不然爲false. if (isCheck ^ $this.treegridExt('isChecked')) { tag = false; return false; } }); //與非: !(T^T)(false)、!(T^F)(true)、!(F^T)(true)、F^F(true) if (!(isCheck || tag)) { //選的不全 parentNode.treegridExt('check', true); parentNode.addClass('treegridExt-partialChecked'); } else if (isCheck) { //全選 parentNode.treegridExt('check', true); parentNode.removeClass('treegridExt-partialChecked'); } else { //全不選 parentNode.treegridExt('check', false); parentNode.removeClass('treegridExt-partialChecked'); } if (!parentNode.treegridExt('getParentNode')) { parentNode.treegridExt('checkUpRecursive', isCheck); } } else { //rootNodes var $this = $(this); var checkCount = 0; var rootNodes = $this.treegridExt('getRootNodes'); $.each(rootNodes, function (index, item) { var $item = $(item); if($item.treegridExt('isChecked')){ checkCount++; } if ($item.treegridExt('isPartialChecked')) { checkCount--; } }); var chkTr = $this.treegridExt('getSetting','getTableHeader').apply(this,[$($this.treegridExt('getTreeContainer'))]); if (checkCount < rootNodes.length) { //全不選,部分選 if (isCheck || checkCount > 0) { //chkTr.find('input[type="checkbox"]').prop('checked',true); chkTr.treegridExt('getSetting', 'getCheckbox').apply($(chkTr)).prop('checked', true); chkTr.removeClass('treegridExt-checkedAll').addClass('treegridExt-partialChecked'); } else { chkTr.treegridExt('getSetting', 'getCheckbox').apply($(chkTr)).prop('checked', false); chkTr.removeClass('treegridExt-checkedAll').removeClass('treegridExt-partialChecked'); } } else { //全選 chkTr.treegridExt('getSetting', 'getCheckbox').apply($(chkTr)).prop('checked', true); chkTr.removeClass('treegridExt-partialChecked').addClass('treegridExt-checkedAll'); } } }, toggleCheck: function () { var $this = $(this); var isCheck = $this.treegridExt('isChecked'); $this.treegridExt('check', !isCheck); $this.treegridExt('checkDownRecursive', !isCheck); $this.treegridExt('checkUpRecursive', !isCheck); return $this; }, toggleCheckAll: function () { var $this = $(this); var chkAll = $this.treegridExt('getSetting', 'getCheckbox').apply(this); var isCheck = $this.treegridExt('isCheckedAll'); if (isCheck) { chkAll.prop('checked', false); $this.removeClass('treegridExt-checkedAll'); } else { chkAll.prop('checked', true); $this.addClass('treegridExt-checkedAll'); } $.each($this.treegridExt('getRootNodes'), function (index, item) { $(item).treegridExt('checkDownRecursive', !isCheck); }); return $this; }, delChecked: function () { alert('這是刪除按鈕啦!'); }, getRootNodes: function () { return $(this).treegrid('getRootNodes'); }, /*bool*/ isChecked: function () { return $(this).hasClass('treegridExt-checked'); }, isPartialChecked: function(){ return $(this).hasClass('treegridExt-partialChecked'); }, isCheckedAll: function () { return $(this).hasClass('treegridExt-checkedAll'); }, isDelAll: function () { return $(this).hasClass('treegridExt-delAll'); }, /*loadData*/ loadData: function (settings) { var $this = $(this); var defData = settings.data; var url = settings.url; if (defData && defData.length >0) { return defData; } else if (url) { $.ajax({ type: settings.type, url: url, data: settings.data, dataType: "JSON", success: function (data, textStatus, jqXHR) { //debugger; if (data && data.length > 0) { //生成表格 $this.treegridExt('renderTable',data); } //初始化Header settings.getTableHeader.apply(this, [$this]).treegridExt('initHeader', settings); //初始化結點 settings.getRootNodes.apply(this, [$this]).treegridExt('initNode', settings); //生成樹 $this.treegridExt('getRootNodes').treegridExt('render'); //默認展開狀態 if (!settings.expandAll) { $this.treegridExt('collapseAll'); } } }); return $this; } }, /*render*/ render: function () { return $(this).each(function () { var $this = $(this); //if parent colapsed we hidden if ($this.treegrid('isOneOfParentsCollapsed')) { $this.hide(); } else { $this.show(); } if (!$this.treegrid('isLeaf')) { $this.treegrid('renderExpander'); $this.treegrid('getChildNodes').treegrid('render'); } }); }, renderExpander: function () { return $(this).each(function () { var $this = $(this); var expander = $this.treegrid('getSetting', 'getExpander').apply(this); if (expander) { if (!$this.treegrid('isCollapsed')) { expander.removeClass($this.treegrid('getSetting', 'expanderCollapsedClass')); expander.addClass($this.treegrid('getSetting', 'expanderExpandedClass')); } else { expander.removeClass($this.treegrid('getSetting', 'expanderExpandedClass')); expander.addClass($this.treegrid('getSetting', 'expanderCollapsedClass')); } } else { $this.treegrid('initExpander'); $this.treegrid('renderExpander'); } }); }, renderTable: function (data) { var $this = $(this); //debugger; //設置表樣式 $this.addClass('table'); if ($this.treegridExt('getSetting', 'striped')) { $this.addClass('table-striped'); } if ($this.treegridExt('getSetting', 'bordered')) { $this.addClass('table-bordered'); } //生成表頭 $this.treegridExt('renderHead'); //生成表體 $this.treegridExt('renderBody', data); return $this; }, renderHead: function () { var $this = $(this); //debugger; var thead = $('<thead></thead>') var thr = $('<tr></tr>'); thr.addClass('treegridExt-header'); $.each($this.treegridExt('getSetting', 'columns'), function (i, item) { var th = $('<th></th>'); th.text(item.title); thr.append(th); }); thr.appendTo(thead); return $this.append(thead); }, renderBody: function (data) { var $this = $(this); var tbody = $('<tbody></tbody>'); var isTreedData = $this.treegridExt('getSetting', 'treedData'); var parentCol = $this.treegridExt('getSetting', 'parentColumn'); var sortCol = $this.treegridExt('getSetting', 'sortColumn'); var cols = $this.treegridExt('getSetting', 'columns'); var rootNodes = getRootNodesFromData(data, isTreedData, parentCol, sortCol); if (rootNodes && rootNodes.length > 0) { $.each(rootNodes, function (i, item) { var tr = $('<tr></tr>'); tr.addClass('treegrid-' + (++nodeCount)); $.each(cols, function (index, column) { var td = $('<td></td>'); td.text(item[column.field]); tr.append(td); }); tbody.append(tr); if ($this.treegridExt('getSetting', 'treedData')) { var childCol = $this.treegridExt('getSetting', 'childrenColumn'); $this.treegridExt('renderTreedDataTr', item, nodeCount, cols, childCol, sortCol, tbody); } else { var idCol = $this.treegridExt('getSetting', 'idColumn'); $this.treegridExt('renderListDataTr', data, item, nodeCount, cols, idCol, parentCol, sortCol, tbody); } }); } return $this.append(tbody); }, renderListDataTr: function (data, parentData, parentIndex, columns, idColumn, parentColumn, sortColumn, tbody) { var nodes = getListChildNodesFromData(data, parentData, idColumn, parentColumn, sortColumn); if (nodes && nodes.length > 0) { $.each(nodes, function (i, item) { var tr = $('<tr></tr>'); var nowParentIndex = ++nodeCount; tr.addClass('treegrid-' + nowParentIndex); tr.addClass('treegrid-parent-' + parentIndex); $.each(columns, function (index, column) { var td = $('<td></td>'); td.text(item[column.field]); tr.append(td); }); tbody.append(tr); $(this).treegridExt('renderListDataTr', data, item, nowParentIndex, columns, idColumn, parentColumn, sortColumn, tbody); }); } }, renderTreedDataTr: function (parentNode, parentIndex, columns, childColumn, sortColumn, tbody) { var nodes = getTreeChildNodesFromdata(parentNode, childColumn, sortColumn); if (nodes && nodes.length > 0) { $each(nodes, function (i, item) { var tr = $('<tr></tr>'); var nowParentIndex = ++nodeCount; tr.addClass('treegrid-' + nowParentIndex); tr.addClass('treegrid-parent-' + parentIndex); $each(columns, function (index, column) { var td = $('<td></td>'); td.text(item[column.field]); tr.append(td); }); tbody.append(tr); $(this).treegridExt('renderTreedDataTr', item, nowParentIndex, columns, childColumn, sortColumn, tbody); }); } }, }; /*default values*/ $.fn.treegridExt.defaults = { idColumn: 'Id', parentColumn: 'ParentId', treeColumn: 0, //在哪一列上顯示展開按鈕 treedData: false, //是否樹化的數據 childrenColumn: null, //含有孩子結點的屬性, 非樹化結構直接值爲null data: [], //構造table的數據集合 type: "GET", //請求數據的ajax類型 url: null, //請求數據的ajax的url ajaxParams: {}, //請求數據的ajax的data屬性 sortColumn: null, //按照哪一列進行排序 striped: false, //是否各行漸變色 bordered: false, //是否顯示邊框 expandAll: true, //是否所有展開 showCheck: true, //是否顯示選擇列 showCheckAll: true, //是否選擇全選列 showDelAll: true, //顯示全刪按鈕 showOperation: true, //是否顯示操做列 columns: [], //列名列值 checkTemplate: '<input type="checkbox" >', delAllTemplate: '<input reset radius2" type="reset" value="刪除" onsubmit="return false"><input type="hidden" >', operationTemplate: '<a href class="btn btn4 btn_pencil" data-toggle="tooltip" style="margin-left:5%" data-trigger="hover" title="編輯" ></a><a href class="btn btn4 btn_trash" style="margin-left:5%;" data-toggle="tooltip" data-trigger="hover" title="刪除"></a>', expanderExpandedClass: 'glyphicon glyphicon-chevron-down', //展開的按鈕的圖標 expanderCollapsedClass: 'glyphicon glyphicon-chevron-right', //縮起的按鈕的圖標 getCheckbox: function () { return $(this).find('input[type="checkbox"]'); }, getDelAll: function () { return $(this).find('input[type="reset"]'); }, getTableHeader: function (treegridContainer) { var result = $.grep(treegridContainer.find('tr'), function (element) { var classNames = $(element).attr('class'); var templateClass = /treegridExt-header/; return templateClass.test(classNames); }); return $(result); }, /*Event*/ onCollpase: null, onExpand: null, onChange: null, onCheck: null }; })(jQuery);
//jquery.treegridExt.css
.treegridExt-checkbox {} .treegridExt-checkboxAll {} .treegridExt-checked {background-color:transparent;} .treegridExt-checkedAll { background-color:transparent;} .treegridExt-partialChecked td { background-color: red; } .treegrid-header {}
//前臺HTMl
List.cshtml片斷
<div class="contenttitle2"> <h3>查詢結果</h3> </div> <form method="post" action=""> <table cellpadding="0" cellspacing="0" border="0" class="stdtable resultBox" id="dynTblList"> <colgroup> <col class="con1" style="width: 5%" /> <col class="con0" style="width: 25%"/> <col class="con1" style="width: 15%"/> <col class="con0" style="width: 10%"/> <col class="con1" style="width: 15%"/> <col class="con0" style="width: 15%"/> <col class="con1"/> </colgroup> </table> </form> </div> @section scripts{ <script type="text/javascript"> $(document).ready(function () { $('#dynTblList').treegridExt({ idColumn: 'DictionaryId', parentColumn: 'DictionaryParentId', treeColumn: 0, //在哪一列上顯示展開按鈕 type: 'GET', //請求數據的ajax類型 url: '/Dictionary/GetSearchData', //請求數據的ajax的url ajaxParams: {}, //請求數據的ajax的data屬性 sortColumn: 'DictionarySeq', striped: true, //是否各行漸變色 bordered: true, //是否顯示邊框 expandAll: false, //是否所有展開 columns: [ { title: '字典項值', field: 'DictionaryValue' }, { title: '字典項鍵', field: 'DictionaryKey' }, { title: '字典項序號', field: 'DictionarySeq' }, { title: '備註1', field: 'DictionaryResrv1' }, { title: '備註2', field: 'DictionaryResrv2' } ] }); }); </script> }
相關圖片, 就從treegrid的源碼包裏面找吧...
最終效果以下: