新上手一个项目, 因而正好想学习下bootstrap, 所以就采用asp.net mvc + bootstrap来做.  因为需要TreeGrid的控件, 本来想用easyUI、LingerUi、DWZ, 但显示效果总觉得不协调. 搜来搜去, 发现了牛人写的 jquery-treegrid, 所以就参考这园子里的两篇文章开始做:

JS组件系列——自己动手封装bootstrap-treegrid组件:      http://www.cnblogs.com/landeanfen/p/6776152.html

JS组件系列——封装自己的JS组件,你也可以:     http://www.cnblogs.com/landeanfen/p/5124542.html

这次目的是扩展jquery-treegrid插件, 实现checkbox的全选、单选, 也照着上文添加了ajax远程获取数据的功能. 虽然后来发现了Kendo UI, 但本着学习的目的, 还是完成了这次的插件扩展功能.

由于常年没有接触过前端, 所以jquery基本语法都磕磕绊绊更别说扩展插件了, 边摸索边做.  待我改完一版本, 才能理解了jquery-treegrid插件的作者真的牛掰:

1. jquery-treegrid思想: 没有硬编码的html, 全部通过css样式实现. 像树形结点的维护、结点的打开与折叠状态, 都是由写在TR元素上的css来实现. 也倒是jquery本身不熟吧, 我第一次见这么少的html来实现的jQuery控件.

2. 插件的结构: 跟上面的总体结构类似, 都是  method{}方法集合、$.fn.treegrid扩展、default{}默认参数对象. 其通过初始化函数initTree来开始渲染table元素, 通过保存控件容器(TreeContainer) -> 保存全局设置(Settings) -> 递归地初始化结点(initNode) -> 为每个结点添加事件(intExpander、initIdent、initEvents、initState、initChangeEvent、initSettingsEvents)来完成最终功能. 整体上有点面向对象的意味, 跟之前自己写的JS差距甚大.

刚开始我也是照着前面两篇的文章来实现了基本的样子, 当我快做完的时候才理解了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来实现的.

总结实现过程的砍儿:

1. 理解插件开发思路及手段, 为什么采用如此结构来组织插件.

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

  1. /*
  2. * jQuery treegrid Plugin 0.3.0
  3. * https://github.com/maxazan/jquery-treegrid
  4. *
  5. * Copyright 2013, Pomazan Max
  6. * Licensed under the MIT licenses.
  7. */
  8. (function($) {
  9.  
  10. var methods = {
  11. /**
  12. * Initialize tree
  13. *
  14. * @param {Object} options
  15. * @returns {Object[]}
  16. */
  17. initTree: function(options) {
  18. var settings = $.extend({}, this.treegrid.defaults, options);
  19. return this.each(function() {
  20. var $this = $(this);
  21. $this.treegrid('setTreeContainer', $(this));
  22. $this.treegrid('setSettings', settings);
  23. settings.getRootNodes.apply(this, [$(this)]).treegrid('initNode', settings);
  24. $this.treegrid('getRootNodes').treegrid('render');
  25. });
  26. },
  27. /**
  28. * Initialize node
  29. *
  30. * @param {Object} settings
  31. * @returns {Object[]}
  32. */
  33. initNode: function(settings) {
  34. return this.each(function() {
  35. var $this = $(this);
  36. $this.treegrid('setTreeContainer', settings.getTreeGridContainer.apply(this));
  37. $this.treegrid('getChildNodes').treegrid('initNode', settings);
  38. $this.treegrid('initExpander').treegrid('initIndent').treegrid('initEvents').treegrid('initState').treegrid('initChangeEvent').treegrid("initSettingsEvents");
  39. });
  40. },
  41. initChangeEvent: function() {
  42. var $this = $(this);
  43. //Save state on change
  44. $this.on("change", function() {
  45. var $this = $(this);
  46. $this.treegrid('render');
  47. if ($this.treegrid('getSetting', 'saveState')) {
  48. $this.treegrid('saveState');
  49. }
  50. });
  51. return $this;
  52. },
  53. /**
  54. * Initialize node events
  55. *
  56. * @returns {Node}
  57. */
  58. initEvents: function() {
  59. var $this = $(this);
  60. //Default behavior on collapse
  61. $this.on("collapse", function() {
  62. var $this = $(this);
  63. $this.removeClass('treegrid-expanded');
  64. $this.addClass('treegrid-collapsed');
  65. });
  66. //Default behavior on expand
  67. $this.on("expand", function() {
  68. var $this = $(this);
  69. $this.removeClass('treegrid-collapsed');
  70. $this.addClass('treegrid-expanded');
  71. });
  72.  
  73. return $this;
  74. },
  75. /**
  76. * Initialize events from settings
  77. *
  78. * @returns {Node}
  79. */
  80. initSettingsEvents: function() {
  81. var $this = $(this);
  82. //Save state on change
  83. $this.on("change", function() {
  84. var $this = $(this);
  85. if (typeof($this.treegrid('getSetting', 'onChange')) === "function") {
  86. $this.treegrid('getSetting', 'onChange').apply($this);
  87. }
  88. });
  89. //Default behavior on collapse
  90. $this.on("collapse", function() {
  91. var $this = $(this);
  92. if (typeof($this.treegrid('getSetting', 'onCollapse')) === "function") {
  93. $this.treegrid('getSetting', 'onCollapse').apply($this);
  94. }
  95. });
  96. //Default behavior on expand
  97. $this.on("expand", function() {
  98. var $this = $(this);
  99. if (typeof($this.treegrid('getSetting', 'onExpand')) === "function") {
  100. $this.treegrid('getSetting', 'onExpand').apply($this);
  101. }
  102.  
  103. });
  104.  
  105. return $this;
  106. },
  107. /**
  108. * Initialize expander for node
  109. *
  110. * @returns {Node}
  111. */
  112. initExpander: function() {
  113. var $this = $(this);
  114. var cell = $this.find('td').get($this.treegrid('getSetting', 'treeColumn'));
  115. var tpl = $this.treegrid('getSetting', 'expanderTemplate');
  116. var expander = $this.treegrid('getSetting', 'getExpander').apply(this);
  117. if (expander) {
  118. expander.remove();
  119. }
  120. $(tpl).prependTo(cell).click(function() {
  121. $($(this).closest('tr')).treegrid('toggle');
  122. });
  123. return $this;
  124. },
  125. /**
  126. * Initialize indent for node
  127. *
  128. * @returns {Node}
  129. */
  130. initIndent: function() {
  131. var $this = $(this);
  132. $this.find('.treegrid-indent').remove();
  133. var tpl = $this.treegrid('getSetting', 'indentTemplate');
  134. var expander = $this.find('.treegrid-expander');
  135. var depth = $this.treegrid('getDepth');
  136. for (var i = 0; i < depth; i++) {
  137. $(tpl).insertBefore(expander);
  138. }
  139. return $this;
  140. },
  141. /**
  142. * Initialise state of node
  143. *
  144. * @returns {Node}
  145. */
  146. initState: function() {
  147. var $this = $(this);
  148. if ($this.treegrid('getSetting', 'saveState') && !$this.treegrid('isFirstInit')) {
  149. $this.treegrid('restoreState');
  150. } else {
  151. if ($this.treegrid('getSetting', 'initialState') === "expanded") {
  152. $this.treegrid('expand');
  153. } else {
  154. $this.treegrid('collapse');
  155. }
  156. }
  157. return $this;
  158. },
  159. /**
  160. * Return true if this tree was never been initialised
  161. *
  162. * @returns {Boolean}
  163. */
  164. isFirstInit: function() {
  165. var tree = $(this).treegrid('getTreeContainer');
  166. if (tree.data('first_init') === undefined) {
  167. tree.data('first_init', $.cookie(tree.treegrid('getSetting', 'saveStateName')) === undefined);
  168. }
  169. return tree.data('first_init');
  170. },
  171. /**
  172. * Save state of current node
  173. *
  174. * @returns {Node}
  175. */
  176. saveState: function() {
  177. var $this = $(this);
  178. if ($this.treegrid('getSetting', 'saveStateMethod') === 'cookie') {
  179.  
  180. var stateArrayString = $.cookie($this.treegrid('getSetting', 'saveStateName')) || '';
  181. var stateArray = (stateArrayString === '' ? [] : stateArrayString.split(','));
  182. var nodeId = $this.treegrid('getNodeId');
  183.  
  184. if ($this.treegrid('isExpanded')) {
  185. if ($.inArray(nodeId, stateArray) === -1) {
  186. stateArray.push(nodeId);
  187. }
  188. } else if ($this.treegrid('isCollapsed')) {
  189. if ($.inArray(nodeId, stateArray) !== -1) {
  190. stateArray.splice($.inArray(nodeId, stateArray), 1);
  191. }
  192. }
  193. $.cookie($this.treegrid('getSetting', 'saveStateName'), stateArray.join(','));
  194. }
  195. return $this;
  196. },
  197. /**
  198. * Restore state of current node.
  199. *
  200. * @returns {Node}
  201. */
  202. restoreState: function() {
  203. var $this = $(this);
  204. if ($this.treegrid('getSetting', 'saveStateMethod') === 'cookie') {
  205. var stateArray = $.cookie($this.treegrid('getSetting', 'saveStateName')).split(',');
  206. if ($.inArray($this.treegrid('getNodeId'), stateArray) !== -1) {
  207. $this.treegrid('expand');
  208. } else {
  209. $this.treegrid('collapse');
  210. }
  211.  
  212. }
  213. return $this;
  214. },
  215. /**
  216. * Method return setting by name
  217. *
  218. * @param {type} name
  219. * @returns {unresolved}
  220. */
  221. getSetting: function(name) {
  222. if (!$(this).treegrid('getTreeContainer')) {
  223. return null;
  224. }
  225. return $(this).treegrid('getTreeContainer').data('settings')[name];
  226. },
  227. /**
  228. * Add new settings
  229. *
  230. * @param {Object} settings
  231. */
  232. setSettings: function(settings) {
  233. $(this).treegrid('getTreeContainer').data('settings', settings);
  234. },
  235. /**
  236. * Return tree container
  237. *
  238. * @returns {HtmlElement}
  239. */
  240. getTreeContainer: function() {
  241. return $(this).data('treegrid');
  242. },
  243. /**
  244. * Set tree container
  245. *
  246. * @param {HtmlE;ement} container
  247. */
  248. setTreeContainer: function(container) {
  249. return $(this).data('treegrid', container);
  250. },
  251. /**
  252. * Method return all root nodes of tree.
  253. *
  254. * Start init all child nodes from it.
  255. *
  256. * @returns {Array}
  257. */
  258. getRootNodes: function () {
  259. return $(this).treegrid('getSetting', 'getRootNodes').apply(this, [$(this).treegrid('getTreeContainer')]);
  260. },
  261. /**
  262. * Method return all nodes of tree.
  263. *
  264. * @returns {Array}
  265. */
  266. getAllNodes: function() {
  267. return $(this).treegrid('getSetting', 'getAllNodes').apply(this, [$(this).treegrid('getTreeContainer')]);
  268. },
  269. /**
  270. * Mthod return true if element is Node
  271. *
  272. * @returns {String}
  273. */
  274. isNode: function() {
  275. return $(this).treegrid('getNodeId') !== null;
  276. },
  277. /**
  278. * Mthod return id of node
  279. *
  280. * @returns {String}
  281. */
  282. getNodeId: function() {
  283. if ($(this).treegrid('getSetting', 'getNodeId') === null) {
  284. return null;
  285. } else {
  286. return $(this).treegrid('getSetting', 'getNodeId').apply(this);
  287. }
  288. },
  289. /**
  290. * Method return parent id of node or null if root node
  291. *
  292. * @returns {String}
  293. */
  294. getParentNodeId: function() {
  295. return $(this).treegrid('getSetting', 'getParentNodeId').apply(this);
  296. },
  297. /**
  298. * Method return parent node or null if root node
  299. *
  300. * @returns {Object[]}
  301. */
  302. getParentNode: function() {
  303. if ($(this).treegrid('getParentNodeId') === null) {
  304. return null;
  305. } else {
  306. return $(this).treegrid('getSetting', 'getNodeById').apply(this, [$(this).treegrid('getParentNodeId'), $(this).treegrid('getTreeContainer')]);
  307. }
  308. },
  309. /**
  310. * Method return array of child nodes or null if node is leaf
  311. *
  312. * @returns {Object[]}
  313. */
  314. getChildNodes: function() {
  315. return $(this).treegrid('getSetting', 'getChildNodes').apply(this, [$(this).treegrid('getNodeId'), $(this).treegrid('getTreeContainer')]);
  316. },
  317. /**
  318. * Method return depth of tree.
  319. *
  320. * This method is needs for calculate indent
  321. *
  322. * @returns {Number}
  323. */
  324. getDepth: function() {
  325. if ($(this).treegrid('getParentNode') === null) {
  326. return 0;
  327. }
  328. return $(this).treegrid('getParentNode').treegrid('getDepth') + 1;
  329. },
  330. /**
  331. * Method return true if node is root
  332. *
  333. * @returns {Boolean}
  334. */
  335. isRoot: function() {
  336. return $(this).treegrid('getDepth') === 0;
  337. },
  338. /**
  339. * Method return true if node has no child nodes
  340. *
  341. * @returns {Boolean}
  342. */
  343. isLeaf: function() {
  344. return $(this).treegrid('getChildNodes').length === 0;
  345. },
  346. /**
  347. * Method return true if node last in branch
  348. *
  349. * @returns {Boolean}
  350. */
  351. isLast: function() {
  352. if ($(this).treegrid('isNode')) {
  353. var parentNode = $(this).treegrid('getParentNode');
  354. if (parentNode === null) {
  355. if ($(this).treegrid('getNodeId') === $(this).treegrid('getRootNodes').last().treegrid('getNodeId')) {
  356. return true;
  357. }
  358. } else {
  359. if ($(this).treegrid('getNodeId') === parentNode.treegrid('getChildNodes').last().treegrid('getNodeId')) {
  360. return true;
  361. }
  362. }
  363. }
  364. return false;
  365. },
  366. /**
  367. * Method return true if node first in branch
  368. *
  369. * @returns {Boolean}
  370. */
  371. isFirst: function() {
  372. if ($(this).treegrid('isNode')) {
  373. var parentNode = $(this).treegrid('getParentNode');
  374. if (parentNode === null) {
  375. if ($(this).treegrid('getNodeId') === $(this).treegrid('getRootNodes').first().treegrid('getNodeId')) {
  376. return true;
  377. }
  378. } else {
  379. if ($(this).treegrid('getNodeId') === parentNode.treegrid('getChildNodes').first().treegrid('getNodeId')) {
  380. return true;
  381. }
  382. }
  383. }
  384. return false;
  385. },
  386. /**
  387. * Return true if node expanded
  388. *
  389. * @returns {Boolean}
  390. */
  391. isExpanded: function() {
  392. return $(this).hasClass('treegrid-expanded');
  393. },
  394. /**
  395. * Return true if node collapsed
  396. *
  397. * @returns {Boolean}
  398. */
  399. isCollapsed: function() {
  400. return $(this).hasClass('treegrid-collapsed');
  401. },
  402. /**
  403. * Return true if at least one of parent node is collapsed
  404. *
  405. * @returns {Boolean}
  406. */
  407. isOneOfParentsCollapsed: function() {
  408. var $this = $(this);
  409. if ($this.treegrid('isRoot')) {
  410. return false;
  411. } else {
  412. if ($this.treegrid('getParentNode').treegrid('isCollapsed')) {
  413. return true;
  414. } else {
  415. return $this.treegrid('getParentNode').treegrid('isOneOfParentsCollapsed');
  416. }
  417. }
  418. },
  419. /**
  420. * Expand node
  421. *
  422. * @returns {Node}
  423. */
  424. expand: function() {
  425. if (!this.treegrid('isLeaf') && !this.treegrid("isExpanded")) {
  426. this.trigger("expand");
  427. this.trigger("change");
  428. return this;
  429. }
  430. return this;
  431. },
  432. /**
  433. * Expand all nodes
  434. *
  435. * @returns {Node}
  436. */
  437. expandAll: function() {
  438. var $this = $(this);
  439. $this.treegrid('getRootNodes').treegrid('expandRecursive');
  440. return $this;
  441. },
  442. /**
  443. * Expand current node and all child nodes begin from current
  444. *
  445. * @returns {Node}
  446. */
  447. expandRecursive: function() {
  448. return $(this).each(function() {
  449. var $this = $(this);
  450. $this.treegrid('expand');
  451. if (!$this.treegrid('isLeaf')) {
  452. $this.treegrid('getChildNodes').treegrid('expandRecursive');
  453. }
  454. });
  455. },
  456. /**
  457. * Collapse node
  458. *
  459. * @returns {Node}
  460. */
  461. collapse: function() {
  462. return $(this).each(function() {
  463. var $this = $(this);
  464. if (!$this.treegrid('isLeaf') && !$this.treegrid("isCollapsed")) {
  465. $this.trigger("collapse");
  466. $this.trigger("change");
  467. }
  468. });
  469. },
  470. /**
  471. * Collapse all nodes
  472. *
  473. * @returns {Node}
  474. */
  475. collapseAll: function() {
  476. var $this = $(this);
  477. $this.treegrid('getRootNodes').treegrid('collapseRecursive');
  478. return $this;
  479. },
  480. /**
  481. * Collapse current node and all child nodes begin from current
  482. *
  483. * @returns {Node}
  484. */
  485. collapseRecursive: function() {
  486. return $(this).each(function() {
  487. var $this = $(this);
  488. $this.treegrid('collapse');
  489. if (!$this.treegrid('isLeaf')) {
  490. $this.treegrid('getChildNodes').treegrid('collapseRecursive');
  491. }
  492. });
  493. },
  494. /**
  495. * Expand if collapsed, Collapse if expanded
  496. *
  497. * @returns {Node}
  498. */
  499. toggle: function() {
  500. var $this = $(this);
  501. if ($this.treegrid('isExpanded')) {
  502. $this.treegrid('collapse');
  503. } else {
  504. $this.treegrid('expand');
  505. }
  506. return $this;
  507. },
  508. /**
  509. * Rendering node
  510. *
  511. * @returns {Node}
  512. */
  513. render: function() {
  514. return $(this).each(function() {
  515. var $this = $(this);
  516. //if parent colapsed we hidden
  517. if ($this.treegrid('isOneOfParentsCollapsed')) {
  518. $this.hide();
  519. } else {
  520. $this.show();
  521. }
  522. if (!$this.treegrid('isLeaf')) {
  523. $this.treegrid('renderExpander');
  524. $this.treegrid('getChildNodes').treegrid('render');
  525. }
  526. });
  527. },
  528. /**
  529. * Rendering expander depends on node state
  530. *
  531. * @returns {Node}
  532. */
  533. renderExpander: function() {
  534. return $(this).each(function() {
  535. var $this = $(this);
  536. var expander = $this.treegrid('getSetting', 'getExpander').apply(this);
  537. if (expander) {
  538.  
  539. if (!$this.treegrid('isCollapsed')) {
  540. expander.removeClass($this.treegrid('getSetting', 'expanderCollapsedClass'));
  541. expander.addClass($this.treegrid('getSetting', 'expanderExpandedClass'));
  542. } else {
  543. expander.removeClass($this.treegrid('getSetting', 'expanderExpandedClass'));
  544. expander.addClass($this.treegrid('getSetting', 'expanderCollapsedClass'));
  545. }
  546. } else {
  547. $this.treegrid('initExpander');
  548. $this.treegrid('renderExpander');
  549. }
  550. });
  551. }
  552. };
  553. $.fn.treegrid = function(method) {
  554. if (methods[method]) {
  555. return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
  556. } else if (typeof method === 'object' || !method) {
  557. return methods.initTree.apply(this, arguments);
  558. } else {
  559. $.error('Method with name ' + method + ' does not exists for jQuery.treegrid');
  560. }
  561. };
  562. /**
  563. * Plugin's default options
  564. */
  565. $.fn.treegrid.defaults = {
  566. initialState: 'expanded',
  567. saveState: false,
  568. saveStateMethod: 'cookie',
  569. saveStateName: 'tree-grid-state',
  570. expanderTemplate: '<span class="treegrid-expander"></span>',
  571. indentTemplate: '<span class="treegrid-indent"></span>',
  572. expanderExpandedClass: 'treegrid-expander-expanded',
  573. expanderCollapsedClass: 'treegrid-expander-collapsed',
  574. treeColumn: 0,
  575. getExpander: function() {
  576. return $(this).find('.treegrid-expander');
  577. },
  578. getNodeId: function() {
  579. var template = /treegrid-([A-Za-z0-9_-]+)/;
  580. if (template.test($(this).attr('class'))) {
  581. return template.exec($(this).attr('class'))[1];
  582. }
  583. return null;
  584. },
  585. getParentNodeId: function() {
  586. var template = /treegrid-parent-([A-Za-z0-9_-]+)/;
  587. if (template.test($(this).attr('class'))) {
  588. return template.exec($(this).attr('class'))[1];
  589. }
  590. return null;
  591. },
  592. getNodeById: function(id, treegridContainer) {
  593. var templateClass = "treegrid-" + id;
  594. return treegridContainer.find('tr.' + templateClass);
  595. },
  596. getChildNodes: function(id, treegridContainer) {
  597. var templateClass = "treegrid-parent-" + id;
  598. return treegridContainer.find('tr.' + templateClass);
  599. },
  600. getTreeGridContainer: function() {
  601. return $(this).closest('table');
  602. },
  603. getRootNodes: function(treegridContainer) {
  604. var result = $.grep(treegridContainer.find('tr'), function(element) {
  605. var classNames = $(element).attr('class');
  606. var templateClass = /treegrid-([A-Za-z0-9_-]+)/;
  607. var templateParentClass = /treegrid-parent-([A-Za-z0-9_-]+)/;
  608. return templateClass.test(classNames) && !templateParentClass.test(classNames);
  609. });
  610. return $(result);
  611. },
  612. getAllNodes: function(treegridContainer) {
  613. var result = $.grep(treegridContainer.find('tr'), function(element) {
  614. var classNames = $(element).attr('class');
  615. var templateClass = /treegrid-([A-Za-z0-9_-]+)/;
  616. return templateClass.test(classNames);
  617. });
  618. return $(result);
  619. },
  620. //Events
  621. onCollapse: null,
  622. onExpand: null,
  623. onChange: null
  624.  
  625. };
  626. })(jQuery);

//jquery.treegrid.css

  1. .treegrid-indent {width:16px; height: 16px; display: inline-block; position: relative;}
  2.  
  3. .treegrid-expander {width:16px; height: 16px; display: inline-block; position: relative; cursor: pointer;}
  4.  
  5. .treegrid-expander-expanded{background-image: url(../img/collapse.png); }
  6. .treegrid-expander-collapsed{background-image: url(../img/expand.png);}

//jquery.treegrid.bootstrap3.js

  1. $.extend($.fn.treegrid.defaults, {
  2. expanderExpandedClass: 'glyphicon glyphicon-chevron-down',
  3. expanderCollapsedClass: 'glyphicon glyphicon-chevron-right'
  4. });

//jquey.cookie.js

  1. /*!
  2. * jQuery Cookie Plugin v1.3.1
  3. * https://github.com/carhartl/jquery-cookie
  4. *
  5. * Copyright 2013 Klaus Hartl
  6. * Released under the MIT license
  7. */
  8. (function (factory) {
  9. if (typeof define === 'function' && define.amd) {
  10. // AMD. Register as anonymous module.
  11. define(['jquery'], factory);
  12. } else {
  13. // Browser globals.
  14. factory(jQuery);
  15. }
  16. }(function ($) {
  17.  
  18. var pluses = /\+/g;
  19.  
  20. function decode(s) {
  21. if (config.raw) {
  22. return s;
  23. }
  24. return decodeURIComponent(s.replace(pluses, ' '));
  25. }
  26.  
  27. function decodeAndParse(s) {
  28. if (s.indexOf('"') === 0) {
  29. // This is a quoted cookie as according to RFC2068, unescape...
  30. s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
  31. }
  32.  
  33. s = decode(s);
  34.  
  35. try {
  36. return config.json ? JSON.parse(s) : s;
  37. } catch(e) {}
  38. }
  39.  
  40. var config = $.cookie = function (key, value, options) {
  41.  
  42. // Write
  43. if (value !== undefined) {
  44. options = $.extend({}, config.defaults, options);
  45.  
  46. if (typeof options.expires === 'number') {
  47. var days = options.expires, t = options.expires = new Date();
  48. t.setDate(t.getDate() + days);
  49. }
  50.  
  51. value = config.json ? JSON.stringify(value) : String(value);
  52.  
  53. return (document.cookie = [
  54. config.raw ? key : encodeURIComponent(key),
  55. '=',
  56. config.raw ? value : encodeURIComponent(value),
  57. options.expires ? '; expires=' + options.expires.toUTCString() : '', // use expires attribute, max-age is not supported by IE
  58. options.path ? '; path=' + options.path : '',
  59. options.domain ? '; domain=' + options.domain : '',
  60. options.secure ? '; secure' : ''
  61. ].join(''));
  62. }
  63.  
  64. // Read
  65. var cookies = document.cookie.split('; ');
  66. var result = key ? undefined : {};
  67. for (var i = 0, l = cookies.length; i < l; i++) {
  68. var parts = cookies[i].split('=');
  69. var name = decode(parts.shift());
  70. var cookie = parts.join('=');
  71.  
  72. if (key && key === name) {
  73. result = decodeAndParse(cookie);
  74. break;
  75. }
  76.  
  77. if (!key) {
  78. result[name] = decodeAndParse(cookie);
  79. }
  80. }
  81.  
  82. return result;
  83. };
  84.  
  85. config.defaults = {};
  86.  
  87. $.removeCookie = function (key, options) {
  88. if ($.cookie(key) !== undefined) {
  89. // Must not alter options, thus extending a fresh object...
  90. $.cookie(key, '', $.extend({}, options, { expires: -1 }));
  91. return true;
  92. }
  93. return false;
  94. };
  95.  
  96. }));

////以上是jquery-treegrid的主要先关内容, 以下是这次扩展的代码

//jquey.treegrid.extention.js

  1. /*
  2. * jQuery treegrid extension 0.1.0
  3. *
  4. * Copyright 2017, Jalen Zhang
  5. * Licensed under the MIT licenses.
  6. */
  7.  
  8. ; (function ($) {
  9. "use strict"; //严格模式下, 全局对象无法使用默认绑定
  10.  
  11. /*begin private functions*/
  12. var nodeCount = 0; //全局结点计数
  13. //从数据中获取跟结点
  14. var getRootNodesFromData = function (data,isTreedData,parentCol,sortCol) {
  15. var result = [];
  16. $.each(data, function (index, item) {
  17. if (isTreedData || !item[parentCol] || item[parentCol] == 0) {
  18. result.push(item);
  19. }
  20. });
  21. if (sortCol) {
  22. result.sort(function (a, b) {
  23. return a[sortCol] - b[sortCol];
  24. });
  25. }
  26. return result;
  27.  
  28. }
  29. //从数据中获取子节点
  30. var getListChildNodesFromData = function (data, parentNode,idCol,parentCol,sortCol) {
  31. var unsort = [];
  32. $.each(data, function (i, item) {
  33. if (item[parentCol] == parentNode[idCol]) {
  34. unsort.push(item);
  35. }
  36. });
  37. if (unsort == null || unsort.length < 1)
  38. return;
  39.  
  40. if (sortCol) {
  41. unsort.sort(function (a, b) {
  42. return a[sortCol] - b[sortCol];
  43. });
  44. }
  45. return unsort;
  46. }
  47. var getTreeChildNodesFromdata = function (parentNode,childCol,sortCol) {
  48. if (childCol) {
  49. var childNodes = parentNode[childCol];
  50. if (sortCol)
  51. childNodes.sort(function (a, b) {
  52. return a[sortCol] - b[sortCol];
  53. });
  54. return childNodes;
  55. }
  56. return null;
  57. }
  58. /*end private functions*/
  59.  
  60. /*Main*/
  61. $.fn.treegridExt = function (method) {
  62. if (methods[method]) {
  63. //如果是调用方法(参数对象中含有方法名)
  64. return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
  65. } else if (typeof method === 'object' || !method) {
  66. //调用初始化函数(参数不含方法名)
  67. return methods.initExtTree.apply(this, arguments);
  68. } else {
  69. $.error('Method with name ' + method + ' does not exists for jQuery.treegridExt');
  70. return this;
  71. }
  72. };
  73.  
  74. /*public functions*/
  75. var methods = {
  76. initExtTree: function (options) {
  77. //获取配置信息
  78. var settings = $.extend({}, this.treegrid.defaults, this.treegridExt.defaults, options || {});
  79. var $this = $(this);
  80. //Code
  81. //设置控件容器
  82. $this.treegridExt('setTreeContainer', $this);
  83. //保存设置
  84. $this.treegridExt('setSettings', settings);
  85. if (!settings.url) {
  86. //载入数据
  87. var data = $this.treegridExt('loadData',settings);
  88. if (data && data.length > 0) {
  89. //生成表格
  90. $this.treegridExt('renderTable',data);
  91. }
  92. //初始化header
  93. settings.getTableHeader.apply(this,[$this]).treegridExt('initHeader',settings);
  94. //初始化结点
  95. settings.getRootNodes.apply(this, [$this]).treegridExt('initNode', settings);
  96. //生成树
  97. $this.treegridExt('getRootNodes').treegridExt('render');
  98. //默认展开状态
  99. if (!settings.expandAll) {
  100. $this.treegridExt('collapseAll');
  101. }
  102. } else {
  103. $this.treegridExt('loadData',settings);
  104. }
  105. return $this;
  106. },
  107. dispose: function (options) {
  108. return $(this).each(function () {
  109. var $this = $(this);
  110. $this.treegridExt('delState');
  111. $this.treegridExt('delSettings');
  112. $this.treegridExt('delTreeContainer');
  113. });
  114. },
  115. val: function (options) {
  116. //获取选择器中第一个元素的html
  117. return this.eq(0).html();
  118. },
  119.  
  120. //##Beigin自定义初始化方法
  121. /*init*/
  122. initHeader: function (settings) {
  123. return this.each(function () {
  124. var $this = $(this);
  125. $this.treegridExt('setTreeContainer', settings.getTreeGridContainer.apply(this));
  126. $this.treegridExt('initCheckAll').treegridExt('initDelAll');
  127. if ($this.treegridExt('getSetting', 'showOperation')) {
  128. var cell = $('<th></th>');
  129. cell.text('操作');
  130. $this.append(cell);
  131. }
  132. return $this;
  133. });
  134. },
  135. initNode: function (settings) {
  136. return this.each(function () {
  137. var $this = $(this);
  138. $this.treegridExt('setTreeContainer', settings.getTreeGridContainer.apply(this));
  139. $this.treegridExt('initExpander').treegridExt('initIndent').treegridExt('initCheck').treegridExt('initOperation').treegridExt('initEvents').treegridExt('initState').treegridExt('initChangeEvent').treegridExt('initSettingsEvents');
  140. $this.treegridExt('getChildNodes').treegridExt('initNode', settings);
  141. });
  142. },
  143. initCheckAll: function () {
  144. var $this = $(this);
  145. if ($this.treegridExt('getSetting', 'showCheck') && $this.treegridExt('getSetting', 'showCheckAll')) {
  146. $this.addClass('treegridExt-checkboxAll');
  147. var cell = $('<th></th>');
  148. var tpl = $this.treegridExt('getSetting', 'checkTemplate');
  149. var checks = $this.treegridExt('getSetting', 'getCheckbox').apply(this);
  150. if (checks && checks.length > 0) {
  151. checks.remove();
  152. }
  153. $this.prepend(cell.append(tpl));
  154. $this.treegridExt('getSetting', 'getCheckbox').apply(this).click(function () { $this.treegridExt('toggleCheckAll'); });
  155. }
  156. return $this;
  157. },
  158. initDelAll: function () {
  159. var $this = $(this);
  160. if ($this.treegridExt('getSetting', 'showCheckAll') && $this.treegridExt('getSetting', 'showDelAll')) {
  161. var cell = $this.find('th').get(0);
  162. var delTpl = $this.treegridExt('getSetting', 'delAllTemplate');
  163. var checks = $this.treegridExt('getSetting', 'getDelAll').apply(this);
  164. if (checks && checks.length > 0) {
  165. checks.remove();
  166. }
  167. $(cell).append(delTpl);
  168. $this.treegridExt('getSetting', 'getDelAll').apply(this).click(function () { $this.treegridExt('delChecked'); });
  169. }
  170. return $this;
  171. },
  172. initCheck: function () {
  173. var $this = $(this);
  174. if ($this.treegridExt('getSetting', 'showCheck')) {
  175. var cell = $('<td></td>');
  176. var tpl = $this.treegridExt('getSetting', 'checkTemplate');
  177. var checks = $this.treegridExt('getSetting', 'getCheckbox');
  178. if (checks && checks.length > 0) {
  179. checks.remove();
  180. }
  181. $this.prepend(cell.append(tpl));
  182. $this.treegridExt('getSetting', 'getCheckbox').apply(this).click(function () { $this.treegridExt('toggleCheck'); });
  183. }
  184. return $this;
  185. },
  186. initOperation: function () {
  187. var $this = $(this);
  188. if ($this.treegridExt('getSetting', 'showOperation')) {
  189. var cell = $('<td></td>');
  190. var tpl = $this.treegridExt('getSetting', 'operationTemplate');
  191. $this.append(cell.append(tpl));
  192. }
  193. return $this;
  194. },
  195. initEvents: function () {
  196. var $this = $(this);
  197. //Default behavior on check
  198. $this.on('check', function () {
  199. var $this = $(this);
  200. $this.addClass('treegrid-checked');
  201. });
  202. //Default behavior on other operations
  203. return $this.treegrid('initEvents');
  204. },
  205. initSettingsEvents: function () {
  206. var $this = $(this);
  207. //Save state on check
  208. $this.on('check', function () {
  209. var $this = $(this);
  210. if (typeof ($this.treegridExt('getSetting', 'onCheck')) === "function") {
  211. $this.treegridExt('getSetting', 'onCheck').apply($this);
  212. }
  213. });
  214. //Save state on other operation
  215. return $this.treegrid('initSettingsEvents');
  216. },
  217. //##end自定义的初始化方法
  218.  
  219. //##Begin原组件的方法的封装
  220. /*init*/
  221. initExpander: function () {
  222. return $(this).treegrid('initExpander');
  223. },
  224. initIndent: function () {
  225. return $(this).treegrid('initIndent');
  226. },
  227. initState: function () {
  228. return $(this).treegrid('initState');
  229. },
  230. initChangeEvent: function () {
  231. var $this = $(this);
  232. //Save state on chagne
  233. $this.on('change', function () {
  234. var $this = $(this);
  235. $this.treegridExt('render');
  236. if ($this.treegridExt('getSetting', 'saveState')) {
  237. $this.treegridExt('saveState');
  238. }
  239. });
  240. return $this;
  241. },
  242. /*init-event*/
  243. /*base*/
  244. getTreeContainer: function () {
  245. return $(this).treegrid('getTreeContainer');
  246. },
  247. setTreeContainer: function (container) {
  248. //扩展插件和原插件使用相同的存储空间
  249. return $(this).treegrid('setTreeContainer', container);
  250. },
  251. getSetting: function (name) {
  252. return $(this).treegrid('getSetting',name);
  253. },
  254. setSettings: function (settings) {
  255. return $(this).treegrid('setSettings',settings);
  256. },
  257. restoreState: function () {
  258. return $(this).treegrid('restoreState');
  259. },
  260. saveState: function () {
  261. return $(this).treegrid('saveState');
  262. },
  263. /*node*/
  264. getAllNodes: function () {
  265. return $(this).treegrid('getAllNodes');
  266. },
  267. getParentNode: function () {
  268. return $(this).treegrid('getParentNode');
  269. },
  270. getChildNodes: function () {
  271. return $(this).treegrid('getChildNodes');
  272. },
  273. /*fake-id*/
  274. getNodeId: function () {
  275. return $(this).treegrid('getNodeId');
  276. },
  277. getParentNodeId: function () {
  278. return $(this).treegrid('getParentNodeId');
  279. },
  280. getDepth: function () {
  281. return $(this).treegrid('getDepth');
  282. },
  283. /*bool*/
  284. isRoot: function () {
  285. return $(this).treegrid('isRoot');
  286. },
  287. isNode: function () {
  288. return $(this).treegrid('isNode');
  289. },
  290. isLeaf: function () {
  291. return $(this).treegrid('isLeaf');
  292. },
  293. isFirst: function () {
  294. return $(this).treegrid('isFirst');
  295. },
  296. isLast: function () {
  297. return $(this).treegrid('isLast');
  298. },
  299. isExpanded: function () {
  300. return $(this).treegrid('isExpanded');
  301. },
  302. isCollapsed: function () {
  303. return $(this).treegrid('isCollapsed');
  304. },
  305. isFirstInit: function () {
  306. return $(this).treegrid('isFirstInit');
  307. },
  308. isOneOfParentsCollapsed: function () {
  309. return $(this).treegrid('isOneOfParentsCollapsed');
  310. },
  311. /*verb*/
  312. expand: function () {
  313. return $(this).treegrid('expand');
  314. },
  315. expandAll: function () {
  316. return $(this).treegrid('expandAll');
  317. },
  318. expandRecursive: function () {
  319. return $(this).treegrid('expandRecursive');
  320. },
  321. collapse: function () {
  322. return $(this).treegrid('collapse');
  323. },
  324. collapseAll: function () {
  325. return $(this).treegrid('collapseAll');
  326. },
  327. collapseRecursive: function () {
  328. return $(this).treegrid('collapseRecursive');
  329. },
  330. /*
  331. toggle: function () {
  332. return $(this).treegrid('toggle').apply(this);
  333. },*/
  334. //##End原组件方法的封装
  335.  
  336. //自定义的方法........
  337. delState: function () {
  338. $.cookie($this.treegridExt('getSetting', 'saveStateName'), null);
  339. },
  340. delSettings: function () {
  341. if (!$(this).treegridExt('getTreeContainer'))
  342. return;
  343. $this.treegridExt('getTreeContainer').removeData('settings');
  344. },
  345. delTreeContainer: function () {
  346. if (!$(this).treegridExt('getTreeContainer'))
  347. return;
  348. return $(this).removeData('treegrid', container);
  349. },
  350. check: function (isCheck) {
  351. var $this = $(this);
  352. if (isCheck) {
  353. $this.treegridExt('getSetting', 'getCheckbox').apply(this).prop('checked',true);
  354. $this.addClass('treegridExt-checked');
  355. if ($this.treegrid('isCollapsed')) {
  356. $this.treegrid('expand');
  357. }
  358. } else {
  359. $this.treegridExt('getSetting', 'getCheckbox').apply(this).prop('checked', false);
  360. $this.removeClass('treegridExt-checked');
  361. }
  362. return $this;
  363. },
  364. checkDownRecursive: function (isCheck) {
  365. //return $(this).each(function () {
  366. var $this = $(this);
  367. $this.treegridExt('check', isCheck);
  368. if (!$this.treegridExt('isLeaf')) {
  369. $this.treegridExt('getChildNodes').treegridExt('checkDownRecursive', isCheck);
  370. }
  371. return $this;
  372. //});
  373. },
  374. checkUpRecursive: function (isCheck) {
  375. var parentNode = $(this).treegridExt('getParentNode');
  376. if (parentNode) {
  377. var tag = true;
  378. $.each(parentNode.treegridExt('getChildNodes'), function () {
  379. var $this = $(this);
  380. //异或: T^T(false)、T^F(true)、F^T(true)、F^F(false), 全选或全不选(true), 否则为false.
  381. if (isCheck ^ $this.treegridExt('isChecked')) {
  382. tag = false;
  383. return false;
  384. }
  385. });
  386. //与非: !(T^T)(false)、!(T^F)(true)、!(F^T)(true)、F^F(true)
  387. if (!(isCheck || tag)) {
  388. //选的不全
  389. parentNode.treegridExt('check', true);
  390. parentNode.addClass('treegridExt-partialChecked');
  391. } else if (isCheck) {
  392. //全选
  393. parentNode.treegridExt('check', true);
  394. parentNode.removeClass('treegridExt-partialChecked');
  395. } else {
  396. //全不选
  397. parentNode.treegridExt('check', false);
  398. parentNode.removeClass('treegridExt-partialChecked');
  399. }
  400. if (!parentNode.treegridExt('getParentNode')) {
  401. parentNode.treegridExt('checkUpRecursive', isCheck);
  402. }
  403. } else {
  404. //rootNodes
  405. var $this = $(this);
  406. var checkCount = 0;
  407. var rootNodes = $this.treegridExt('getRootNodes');
  408. $.each(rootNodes, function (index, item) {
  409. var $item = $(item);
  410. if($item.treegridExt('isChecked')){
  411. checkCount++;
  412. }
  413. if ($item.treegridExt('isPartialChecked')) {
  414. checkCount--;
  415. }
  416. });
  417. var chkTr = $this.treegridExt('getSetting','getTableHeader').apply(this,[$($this.treegridExt('getTreeContainer'))]);
  418. if (checkCount < rootNodes.length) {
  419. //全不选,部分选
  420. if (isCheck || checkCount > 0) {
  421. //chkTr.find('input[type="checkbox"]').prop('checked',true);
  422. chkTr.treegridExt('getSetting', 'getCheckbox').apply($(chkTr)).prop('checked', true);
  423. chkTr.removeClass('treegridExt-checkedAll').addClass('treegridExt-partialChecked');
  424. } else {
  425. chkTr.treegridExt('getSetting', 'getCheckbox').apply($(chkTr)).prop('checked', false);
  426. chkTr.removeClass('treegridExt-checkedAll').removeClass('treegridExt-partialChecked');
  427. }
  428. } else {
  429. //全选
  430. chkTr.treegridExt('getSetting', 'getCheckbox').apply($(chkTr)).prop('checked', true);
  431. chkTr.removeClass('treegridExt-partialChecked').addClass('treegridExt-checkedAll');
  432. }
  433.  
  434. }
  435. },
  436. toggleCheck: function () {
  437. var $this = $(this);
  438. var isCheck = $this.treegridExt('isChecked');
  439. $this.treegridExt('check', !isCheck);
  440. $this.treegridExt('checkDownRecursive', !isCheck);
  441. $this.treegridExt('checkUpRecursive', !isCheck);
  442. return $this;
  443. },
  444. toggleCheckAll: function () {
  445. var $this = $(this);
  446. var chkAll = $this.treegridExt('getSetting', 'getCheckbox').apply(this);
  447. var isCheck = $this.treegridExt('isCheckedAll');
  448. if (isCheck) {
  449. chkAll.prop('checked', false);
  450. $this.removeClass('treegridExt-checkedAll');
  451. } else {
  452. chkAll.prop('checked', true);
  453. $this.addClass('treegridExt-checkedAll');
  454. }
  455. $.each($this.treegridExt('getRootNodes'), function (index, item) {
  456. $(item).treegridExt('checkDownRecursive', !isCheck);
  457. });
  458. return $this;
  459. },
  460. delChecked: function () {
  461. alert('这是删除按钮啦!');
  462. },
  463. getRootNodes: function () {
  464. return $(this).treegrid('getRootNodes');
  465. },
  466. /*bool*/
  467. isChecked: function () {
  468. return $(this).hasClass('treegridExt-checked');
  469. },
  470. isPartialChecked: function(){
  471. return $(this).hasClass('treegridExt-partialChecked');
  472. },
  473. isCheckedAll: function () {
  474. return $(this).hasClass('treegridExt-checkedAll');
  475. },
  476. isDelAll: function () {
  477. return $(this).hasClass('treegridExt-delAll');
  478. },
  479. /*loadData*/
  480. loadData: function (settings) {
  481. var $this = $(this);
  482. var defData = settings.data;
  483. var url = settings.url;
  484. if (defData && defData.length >0) {
  485. return defData;
  486. } else if (url) {
  487. $.ajax({
  488. type: settings.type,
  489. url: url,
  490. data: settings.data,
  491. dataType: "JSON",
  492. success: function (data, textStatus, jqXHR) {
  493. //debugger;
  494. if (data && data.length > 0) {
  495. //生成表格
  496. $this.treegridExt('renderTable',data);
  497. }
  498. //初始化Header
  499. settings.getTableHeader.apply(this, [$this]).treegridExt('initHeader', settings);
  500. //初始化结点
  501. settings.getRootNodes.apply(this, [$this]).treegridExt('initNode', settings);
  502. //生成树
  503. $this.treegridExt('getRootNodes').treegridExt('render');
  504. //默认展开状态
  505. if (!settings.expandAll) {
  506. $this.treegridExt('collapseAll');
  507. }
  508. }
  509. });
  510. return $this;
  511. }
  512. },
  513. /*render*/
  514. render: function () {
  515. return $(this).each(function () {
  516. var $this = $(this);
  517. //if parent colapsed we hidden
  518. if ($this.treegrid('isOneOfParentsCollapsed')) {
  519. $this.hide();
  520. } else {
  521. $this.show();
  522. }
  523. if (!$this.treegrid('isLeaf')) {
  524. $this.treegrid('renderExpander');
  525. $this.treegrid('getChildNodes').treegrid('render');
  526. }
  527. });
  528. },
  529. renderExpander: function () {
  530. return $(this).each(function () {
  531. var $this = $(this);
  532. var expander = $this.treegrid('getSetting', 'getExpander').apply(this);
  533. if (expander) {
  534.  
  535. if (!$this.treegrid('isCollapsed')) {
  536. expander.removeClass($this.treegrid('getSetting', 'expanderCollapsedClass'));
  537. expander.addClass($this.treegrid('getSetting', 'expanderExpandedClass'));
  538. } else {
  539. expander.removeClass($this.treegrid('getSetting', 'expanderExpandedClass'));
  540. expander.addClass($this.treegrid('getSetting', 'expanderCollapsedClass'));
  541. }
  542. } else {
  543. $this.treegrid('initExpander');
  544. $this.treegrid('renderExpander');
  545. }
  546. });
  547. },
  548. renderTable: function (data) {
  549. var $this = $(this);
  550. //debugger;
  551. //设置表样式
  552. $this.addClass('table');
  553. if ($this.treegridExt('getSetting', 'striped')) {
  554. $this.addClass('table-striped');
  555. }
  556. if ($this.treegridExt('getSetting', 'bordered')) {
  557. $this.addClass('table-bordered');
  558. }
  559. //生成表头
  560. $this.treegridExt('renderHead');
  561. //生成表体
  562. $this.treegridExt('renderBody', data);
  563. return $this;
  564. },
  565. renderHead: function () {
  566. var $this = $(this);
  567. //debugger;
  568. var thead = $('<thead></thead>')
  569. var thr = $('<tr></tr>');
  570. thr.addClass('treegridExt-header');
  571. $.each($this.treegridExt('getSetting', 'columns'), function (i, item) {
  572. var th = $('<th></th>');
  573. th.text(item.title);
  574. thr.append(th);
  575. });
  576. thr.appendTo(thead);
  577. return $this.append(thead);
  578. },
  579. renderBody: function (data) {
  580. var $this = $(this);
  581. var tbody = $('<tbody></tbody>');
  582. var isTreedData = $this.treegridExt('getSetting', 'treedData');
  583. var parentCol = $this.treegridExt('getSetting', 'parentColumn');
  584. var sortCol = $this.treegridExt('getSetting', 'sortColumn');
  585. var cols = $this.treegridExt('getSetting', 'columns');
  586. var rootNodes = getRootNodesFromData(data, isTreedData, parentCol, sortCol);
  587. if (rootNodes && rootNodes.length > 0) {
  588. $.each(rootNodes, function (i, item) {
  589. var tr = $('<tr></tr>');
  590. tr.addClass('treegrid-' + (++nodeCount));
  591. $.each(cols, function (index, column) {
  592. var td = $('<td></td>');
  593. td.text(item[column.field]);
  594. tr.append(td);
  595. });
  596. tbody.append(tr);
  597. if ($this.treegridExt('getSetting', 'treedData')) {
  598. var childCol = $this.treegridExt('getSetting', 'childrenColumn');
  599. $this.treegridExt('renderTreedDataTr', item, nodeCount, cols, childCol, sortCol, tbody);
  600. } else {
  601. var idCol = $this.treegridExt('getSetting', 'idColumn');
  602. $this.treegridExt('renderListDataTr', data, item, nodeCount, cols, idCol, parentCol, sortCol, tbody);
  603. }
  604. });
  605. }
  606. return $this.append(tbody);
  607. },
  608. renderListDataTr: function (data, parentData, parentIndex, columns, idColumn, parentColumn, sortColumn, tbody) {
  609. var nodes = getListChildNodesFromData(data, parentData, idColumn, parentColumn, sortColumn);
  610. if (nodes && nodes.length > 0) {
  611. $.each(nodes, function (i, item) {
  612. var tr = $('<tr></tr>');
  613. var nowParentIndex = ++nodeCount;
  614. tr.addClass('treegrid-' + nowParentIndex);
  615. tr.addClass('treegrid-parent-' + parentIndex);
  616. $.each(columns, function (index, column) {
  617. var td = $('<td></td>');
  618. td.text(item[column.field]);
  619. tr.append(td);
  620. });
  621. tbody.append(tr);
  622. $(this).treegridExt('renderListDataTr', data, item, nowParentIndex, columns, idColumn, parentColumn, sortColumn, tbody);
  623. });
  624. }
  625. },
  626. renderTreedDataTr: function (parentNode, parentIndex, columns, childColumn, sortColumn, tbody) {
  627. var nodes = getTreeChildNodesFromdata(parentNode, childColumn, sortColumn);
  628. if (nodes && nodes.length > 0) {
  629. $each(nodes, function (i, item) {
  630. var tr = $('<tr></tr>');
  631. var nowParentIndex = ++nodeCount;
  632. tr.addClass('treegrid-' + nowParentIndex);
  633. tr.addClass('treegrid-parent-' + parentIndex);
  634. $each(columns, function (index, column) {
  635. var td = $('<td></td>');
  636. td.text(item[column.field]);
  637. tr.append(td);
  638. });
  639. tbody.append(tr);
  640. $(this).treegridExt('renderTreedDataTr', item, nowParentIndex, columns, childColumn, sortColumn, tbody);
  641. });
  642. }
  643. },
  644. };
  645.  
  646. /*default values*/
  647. $.fn.treegridExt.defaults = {
  648. idColumn: 'Id',
  649. parentColumn: 'ParentId',
  650. treeColumn: 0, //在哪一列上显示展开按钮
  651. treedData: false, //是否树化的数据
  652. childrenColumn: null, //含有孩子结点的属性, 非树化结构直接值为null
  653. data: [], //构造table的数据集合
  654. type: "GET", //请求数据的ajax类型
  655. url: null, //请求数据的ajax的url
  656. ajaxParams: {}, //请求数据的ajax的data属性
  657. sortColumn: null, //按照哪一列进行排序
  658. striped: false, //是否各行渐变色
  659. bordered: false, //是否显示边框
  660. expandAll: true, //是否全部展开
  661. showCheck: true, //是否显示选择列
  662. showCheckAll: true, //是否选择全选列
  663. showDelAll: true, //显示全删按钮
  664. showOperation: true, //是否显示操作列
  665. columns: [], //列名列值
  666. checkTemplate: '<input type="checkbox" >',
  667. delAllTemplate: '<input reset radius2" type="reset" value="删除" onsubmit="return false"><input type="hidden" >',
  668. 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>',
  669. expanderExpandedClass: 'glyphicon glyphicon-chevron-down', //展开的按钮的图标
  670. expanderCollapsedClass: 'glyphicon glyphicon-chevron-right', //缩起的按钮的图标
  671. getCheckbox: function () {
  672. return $(this).find('input[type="checkbox"]');
  673. },
  674. getDelAll: function () {
  675. return $(this).find('input[type="reset"]');
  676. },
  677. getTableHeader: function (treegridContainer) {
  678. var result = $.grep(treegridContainer.find('tr'), function (element) {
  679. var classNames = $(element).attr('class');
  680. var templateClass = /treegridExt-header/;
  681. return templateClass.test(classNames);
  682. });
  683. return $(result);
  684. },
  685. /*Event*/
  686. onCollpase: null,
  687. onExpand: null,
  688. onChange: null,
  689. onCheck: null
  690.  
  691. };
  692. })(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的源码包里面找吧...

最终效果如下:

[原创] 扩展jquery-treegrid插件, 实现勾选功能和全删按钮.的更多相关文章

  1. JQuery表格插件DataTables 当前页合计功能

    公司项目表格插件使用的是DataTables,最近添加表合计功能,发现百度统一都是如图类型的代码,不知道是配置问题还是怎么了,在我的页面下根本不能用 var addd=0; $(document).r ...

  2. 勾选checkbox之后,button按钮可用

    js:function chkClick() {    if (document.getElementById("chkBox").checked == true) {       ...

  3. JQuery实现表格的全选和反选,以及分页勾选保存(laypage插件分页的使用)

    需求: 1.全选与取消全选 2.单个勾选,点击表格单元格中checkbox勾选,也可以在点击行勾选,便与用户操作 3.分页勾选保存 4.固定表头 功能一: 说明:操作全选按钮的同时,遍历每一个tr中的 ...

  4. 获取EasyUI的treegrid的checkbox所有已勾选的数据

    EasyUI为TreeGrid的已勾选节点,未勾选节点,只勾选部分子节点的父节点分别添加了三个不同的样式,如下:样式一:tree-checkbox2 有子节点被选中样式二:tree-checkbox1 ...

  5. 基于 jQuery Jcrop 插件的功能模块:头像剪裁

    /** Jcrop version: 0.9.12 jQuery version: 1.9.0 Author: 小dee Date: 2014.10.30 */ 先看看他山之石:博客园的头像模块也是使 ...

  6. 为jQuery写插件

    很多场合,我们都会调用jQuery的插件去完成某个功能,比如slider. 如下图,做一个div,通过“$( "#slider" ).slider();”的方式直接将div变成sl ...

  7. 解决el-tree lazy懒加载时,连续勾选前两个子节点后第二次进入默认选中时,将父节点也勾选的问题

    在用到el-tree的懒加载和默认勾选功能时,若第一次勾选前几个连续节点,第二次进入默认勾选时,由于el-tree子节点尚未完全加载(只加载出来前几个),默认勾选已经开始(已加载出来的子节点被默认勾选 ...

  8. AngularJS--购物车全选/取消全选功能实现

    刚学习angularJS,于是练习写了一个类似于购物车的全选/取消全选的功能,主要实现的功能有: 1.勾选全选checkbox,列表数据全部被勾选,取消同理,用ng-model实现双向绑定: 2.选中 ...

  9. 解决jquery操作checkbox全选全不选无法勾选问题

    最近在学习中使用jquery操作checkbox,使用下面方法进行全选.反选:$("input[name='checkbox']").attr("checked" ...

随机推荐

  1. PageHelper 自动去掉排序参数问题

    PageHelper.startPage( req.getCurrent()   , req.getSize() ,"ordersCreateDate desc" ); 如果 上面 ...

  2. update_engine-DownloadAction(二)

    在update_engine-DownloadAction(一)中对DownloadAction介绍到了DeltaPerformer的Write方法.下面开始介绍Write方法. src/system ...

  3. Assets Library开发总结

    Assets Library beta版的开发工作告一段落,本着有始有终的原则,这个项目还是需要做个总结的,恩~ 先甩一个链接:https://vimeo.com/238186671 考虑到该项目开发 ...

  4. 【C++】ubuntu中读取指定目录中的所有文件

    摘要:ubuntu系统下,C++程序读取指定文件夹中多个文件,保存文件名列表.文件名没有规律且不考虑读取子文件夹中的文件. 系统配置:ubuntu16.04, cmake编译 首先安利一个函数,输入s ...

  5. JavaScript易混淆的零碎知识点积累

    1.callee属性 和 caller属性. 区别:两者的调用对象不同 arguments.callee:指向拥有这个arguments对象的函数,在递归运算中经常用到. functionName.c ...

  6. scrapy爬虫框架学习笔记(一)

    scrapy爬虫框架学习笔记(一) 1.安装scrapy pip install scrapy 2.新建工程: (1)打开命令行模式 (2)进入要新建工程的目录 (3)运行命令: scrapy sta ...

  7. gin的url查询参数解析

    gin作为go语言最知名的网络库,在这里我简要介绍一下url的查询参数解析.主要是这里面存在一些需要注意的地方.这里,直接给出代码,和运行结果,在必要的地方进行分析. 代码1: type Struct ...

  8. su: Authentication failure问题

    问题: su命令不能切换root,提示错误su: Authentication failure 解决: 使用命令 sudo passwd root 下次再su的时候只要输入密码就可以成功登录了.

  9. 五、使用druid管理数据库,mybatis连接mysql数据库

    简介:    使用 mybatis 连接 mysql 数据库, 一套简单的增删改查流程, 前台用 bootstrap, bootstrap-table 框架, 最后用 druid 监控数据库连接情况 ...

  10. Hbase常见错误解决方法

    Hbase常见错误解决方法 原文转载至:https://www.jianshu.com/p/5fd74812c56c   我是通过maven管理的依赖,直接修改maven依赖中hbase的版本就可以了 ...