已知JQWidgets的TreeGrid组件依赖于jqxcore.js、jqxtreegrid.js,实际上它还依赖于jqxdatatable.js。我们先通过一个例子,来探索本次的话题。

需求:

图1

如图,我们有个表格,它具有【收起-展开】的功能,图中标红的部分是JQWidgets的expand-button模型。

目前默认是第一列,根据系统的实际需求,处理人可以串联邀请多个其他的处理人进行审批工作,那我们在展示时,应该针对审批结果来渲染【收起-展开】的按钮(用户是先关注结果,结果是串联,然后再点击展开,查看哪些人被邀请)。

但翻遍了官方API,也没有看到有接口可以改变expand-button所在的列,最后跟踪源码,发现了一些端倪。

解决方案探索:

 

  我们先来跟踪初始化函数、看一下TreeGrid的大致执行流程。

1、当我们调用 $("#treeGrid").jqxTreeGrid(iniObj)时,他首先进入到jqxcore.js中,分析断点行处的a.jqx.applyWidget函数,顾名思义,类似于js的apply函数,其中参数c为我们的treeGrid的HTMLElement,参数f为"jqxTreeGrid"字符串,参数b就是我们初始化时的赋予的对象(iniObj)。由此我们可以知道TreeGrid初始化时,是先经过jqxcore.js进行中转,jqxcore.js的a.fn[f]类似一个中转器。

备注:如果没有特殊的配置,一般是调用applyWidget方法,断点处d=a.data(c,f),a实际上就是JQuery,根据笔者测试 $.data(name,value) 似乎默认都是返回undefined。

图2

2、控制权到了applyWidget的具体实现,他有一个关键的调用e.createInstanced(d)。

  

d是我们传入的参数对象iniObj

e是在上面有一段代码进行初始化(LIne:3360)

e ? (e.host = g, e.element = b) : e = new a.jqx["_" + c],"" == b.id && (b.id = a.jqx.utilities.createId())

由第一步可知,e根本没有传入,所以此处e实际上就等于new a.jqx["_"+c];//c=jqxTreeGrid。

到此,我们总结一下前面的步骤,当我们在调用$("#treeGrid").jqxTreeGrid(iniObj)时,代码会走到 a.jqx.applyWidge方法中,而jqxTreeGrid方法最终会作为一个字符串参数传入到a.jqx.applyWidget。

而后,我们分析applyWidget的代码实现,我们可以简单认为,$("#treeGrid").jqxTreeGrid(iniObj) 实际上就是 a.jqx["_jqxTreeGrid"].createInstance(iniObj)。

图3

3、当我们进入createInstanced方法时,会发现,代码居然进入到了神秘的jqxdatatable.js(图4),而后再次走下去才进入到jqxtreegrid.js(图5)。

图4

图5

实际上,在第二步时,我们忽略了一个关键代码:代码其实是在循环中调用e.createInstance时,而循环的主体是变量i,往上看,i的赋值代码如下:

 for (var i = new Array, e = h.instance; e;) e.isInitialized = !1,i.push(e),e = e.base;

  我们发现i的值实际上是push进去的,所以我们可以得出结论:jqxTreeGrid对象的base属性是一个jqxdatatable对象!!

我们打开jqxtreegrid.js,目光锁定第8行,jqxtreegrid.js果然和jqxDataTable有关系,再根据base属性的意思,我们猜想这个JqxTreeGrid是基于JqxDataTable实现的(得出这个结论似乎没什么卵用 ((╯' - ')╯ ┻━┻ )

好了,我们回到关键问题,目前我们大致了解数据流向以及总体结构,我们的问题是想要修改expand-button所在的列,看着似乎比较远,但实际上以及差不多摸到真相了。

图6

4、总体浏览一下jqxtreegrid.js文件,发现文件并不大,不到一千行代码,该文件主要声明了一些TreeGrid特有的方法和关键的_renderrows方法,众所周知,一般框架都会存在一个rederer渲染器,渲染器一般是根据对象内部数据进行html元素的描绘,因此,我们聚焦这个_renderrows方法。

在jqxTreeGrid中,如果想要拥有【收起-展开】的功能,则需要在dataAdapter中定义hierarchy属性(dataAdapter的例子可以参考笔者的另外一篇文章),所以,我们现在_renderrows方法中搜索hierarchy这关键字。

经过笔者煞费苦心的跟踪、分析代码,最后定位到jqxtreegrid.js中Line:300-Line:447行就是 画表格的关键代码,且我们一直寻找的expand-button也在其中。先附上jqxtreegrid.js中Line:300-Line:447行的代码

for (var K = b.source._source.hierarchy && b.source._source.hierarchy.groupingDataFields ? b.source.s_ource.hierarchy.groupingDataFields.length : 0, L = 0; L < j.length; L++) {var M = j[L],N = M.uid;K > 0 && M[d.level] < K && (N = M.uid),void 0 === M.uid && (M.uid = b.dataview.generatekey());var F = '<tr data-key="' + N + '" role="row" id="row' + L + b.element.id + '">',O = '<tr data-key="' + N + '" role="row" id="row' + L + b.element.id + '">';if (M.aggregate) var F = '<tr data-role="summaryrow" role="row" id="row' + L + b.element.id + '">',O = '<tr data-role="summaryrow" role="row" id="row' + L + b.element.id + '">';var P = 0;if (b.rowinfo[N]) void 0 === b.rowinfo[N].checked && (b.rowinfo[N].checked = M[d.checked]),void 0 === b.rowinfo[N].icon && (b.rowinfo[N].icon = M[d.icon]),void 0 === b.rowinfo[N].aggregate && (b.rowinfo[N].aggregate = M[d.aggregate]),void 0 === b.rowinfo[N].row && (b.rowinfo[N].row = M),void 0 === b.rowinfo[N].leaf && (b.rowinfo[N].leaf = M[d.leaf]),void 0 === b.rowinfo[N].expanded && (b.rowinfo[N].expanded = M[d.expanded]);else {var Q = M[d.checked];void 0 === Q && (Q = !1),b.rowinfo[N] = {selected: M[d.selected],checked: Q,icon: M[d.icon],aggregate: M.aggregate,row: M,leaf: M[d.leaf],expanded: M[d.expanded]}}var R = b.rowinfo[N];R.row = M,M.originalRecord && (R.originalRecord = M.originalRecord);for (var S = 0, u = 0; u < h; u++) {var T = b.columns.records[u];(T.pinned || b.rtl && b.columns.records[h - 1].pinned) && (E = !0);var w = T.width;w < T.minwidth && (w = T.minwidth),w > T.maxwidth && (w = T.maxwidth),w -= s,w < 0 && (w = 0);var g = b.toTP("jqx-cell") + " " + b.toTP("jqx-grid-cell") + " " + b.toTP("jqx-item");T.pinned && (g += " " + b.toTP("jqx-grid-cell-pinned")),b.sortcolumn === T.displayfield && (g += " " + b.toTP("jqx-grid-cell-sort")),b.altRows && L % 2 != 0 && (g += " " + b.toTP("jqx-grid-cell-alt")),b.rtl && (g += " " + b.toTP("jqx-cell-rtl"));var U = "";if (K > 0 && !i && !M.aggregate && M[d.level] < K) {U += ' colspan="' + h + '"';for (var D = 0, V = 0; V < h; V++) {var W = b.columns.records[V];if (!W.hidden) {var X = W.width;X < W.minwidth && (w = W.minwidth),X > W.maxwidth && (w = W.maxwidth),X -= s,X < 0 && (X = 0),D += X}}w = D}var x = '<td role="gridcell"' + U + ' style="max-width:' + w + "px; width:" + w + "px;",Y = '<td role="gridcell"' + U + ' style="pointer-events: none; visibility: hidden; border-color: transparent; max-width:' + w + "px; width:" + w + "px;";u == h - 1 && 1 == h && (x += "border-right-color: transparent;", Y += "border-right-color: transparent;"),K > 0 && M[d.level] < K && !M.aggregate ? b.rtl && (g += " " + b.toTP("jqx-right-align")) : "left" != T.cellsalign && (g += "right" === T.cellsalign ? " " + b.toTP("jqx-right-align") : " " + b.toTP("jqx-center-align")),R && (R.selected && b.editKey !== N && "none" !== b.selectionMode && (g += " " + b.toTP("jqx-grid-cell-selected"), g += " " + b.toTP("jqx-fill-state-pressed")), R.locked && (g += " " + b.toTP("jqx-grid-cell-locked")), R.aggregate && (g += " " + b.toTP("jqx-grid-cell-pinned"))),T.hidden ? (x += "display: none;", Y += "display: none;", b._hiddencolumns = !0) : (0 != S || b.rtl ? (x += "border-right-width: 0px;", Y += "border-right-width: 0px;") : (x += "border-left-width: 0px;", Y += "border-left-width: 0px;"), S++, P += s + w),T.pinned && (x += "pointer-events: auto;", Y += "pointer-events: auto;");var Z = "";if (0 != b.source.hierarchy.length && M.records && (!M.records || 0 !== M.records.length) || this.virtualModeCreateRecords || (R.leaf = !0), M.records && M.records.length > 0 && (R.leaf = !1), b.dataview.filters.length > 0 && M.records && M.records.length > 0) {for (var $ = !1, _ = 0; _ < M.records.length; _++) if (M.records[_]._visible !== !1 && void 0 == M.records[_].aggregate) {$ = !0;break}$ ? R.leaf = !1 : R.leaf = !0}R && !R.leaf && (R.expanded ? (Z += b.toTP("jqx-tree-grid-expand-button") + " ", Z += b.rtl ? b.toTP("jqx-grid-group-expand-rtl") : b.toTP("jqx-grid-group-expand"), Z += " " + b.toTP("jqx-icon-arrow-down")) : (Z += b.toTP("jqx-tree-grid-collapse-button") + " ", b.rtl ? (Z += b.toTP("jqx-grid-group-collapse-rtl"), Z += " " + b.toTP("jqx-icon-arrow-left")) : (Z += b.toTP("jqx-grid-group-collapse"), Z += " " + b.toTP("jqx-icon-arrow-right")))),(!b.autoRowHeight || 1 === S || b.autoRowHeight && !T.autoCellHeight) && (g += " " + b.toTP("jqx-grid-cell-nowrap"));var aa = b._getcellvalue(T, R.row);if (K > 0 && !M.aggregate && M[d.level] < K && (aa = M.label), "" != T.cellsFormat && a.jqx.dataFormat && (a.jqx.dataFormat.isDate(aa) ? aa = a.jqx.dataFormat.formatdate(aa, T.cellsFormat, b.gridlocalization) : (a.jqx.dataFormat.isNumber(aa) || !isNaN(parseFloat(aa)) && isFinite(aa)) && (aa = a.jqx.dataFormat.formatnumber(aa, T.cellsFormat, b.gridlocalization))), "" != T.cellclassname && T.cellclassname) if ("string" == typeof T.cellclassname) g += " " + T.cellclassname;else {var ba = T.cellclassname(L, T.datafield, b._getcellvalue(T, R.row), R.row, aa);ba && (g += " " + ba)}if ("" != T.cellsRenderer && T.cellsRenderer) {var ca = T.cellsRenderer(N, T.datafield, b._getcellvalue(T, R.row), R.row, aa);void 0 !== ca && (aa = ca)}if (R.aggregate && T.aggregates) {var da = M.siblings.slice(0, M.siblings.length - 1),ea = b._calculateaggregate(T, null, !0, da);if (M[T.displayfield] = "", ea) if (T.aggregatesRenderer) {if (ea) {var fa = T.aggregatesRenderer(ea[T.datafield], T, null, b.getcolumnaggregateddata(T.datafield, T.aggregates, !1, da), "subAggregates");aa = fa,M[T.displayfield] += name + ":" + ea[T.datafield] + "\n"}} else aa = "",M[T.displayfield] = "",a.each(ea, function () {var a = this;for (obj in a) {var c = obj;c = b._getaggregatename(c);var d = '<div style="position: relative; margin: 0px; overflow: hidden;">' + c + ":" + a[obj] + "</div>";aa += d,M[T.displayfield] += c + ":" + a[obj] + "\n"}});else aa = ""}if (1 === S && !b.rtl || T == C && b.rtl || K > 0 && M[d.level] < K) {for (var ga = "", ha = b.toThemeProperty("jqx-tree-grid-indent"), ia = R.leaf ? 1 : 0, ja = 0; ja < M[d.level] + ia; ja++) ga += "<span class='" + ha + "'></span>";var ka = "<span class='" + Z + "'></span>",la = "",ma = "";if (this.checkboxes && !M.aggregate) {var na = b.toThemeProperty("jqx-tree-grid-checkbox") + " " + ha + " " + b.toThemeProperty("jqx-checkbox-default") + " " + b.toThemeProperty("jqx-fill-state-normal") + " " + b.toThemeProperty("jqx-rc-all"),oa = !0;if (a.isFunction(this.checkboxes) && (oa = this.checkboxes(N, M), void 0 == oa && (oa = !1)), oa) if (R) {var pa = R.checked;0 == this.hierarchicalCheckboxes && null === pa && (pa = !1),la += pa ? "<span class='" + na + "'><div class='" + b.toThemeProperty("jqx-tree-grid-checkbox-tick") + " " + b.toThemeProperty("jqx-checkbox-check-checked") + "'></div></span>" : pa === !1 ? "<span class='" + na + "'></span>" : "<span class='" + na + "'><div class='" + b.toThemeProperty("jqx-tree-grid-checkbox-tick") + " " + b.toThemeProperty("jqx-checkbox-check-indeterminate") + "'></div></span>"} else la += "<span class='" + na + "'></span>"}if (this.icons && !M.aggregate) {var qa = b.toThemeProperty("jqx-tree-grid-icon") + " " + ha;if (b.rtl) var qa = b.toThemeProperty("jqx-tree-grid-icon") + " " + b.toThemeProperty("jqx-tree-grid-icon-rtl") + " " + ha;var ra = b.toThemeProperty("jqx-tree-grid-icon-size") + " " + ha,sa = R.icon;a.isFunction(this.icons) && (R.icon = this.icons(N, M), R.icon && (sa = !0)),sa && (ma += R.icon ? "<span class='" + qa + "'><img class='" + ra + "' src='" + R.icon + "'/></span>" : "<span class='" + qa + "'></span>")}var ta = b.autoRowHeight && 1 === S && T.autoCellHeight ? " " + b.toTP("jqx-grid-cell-wrap") : "",ua = ga + ka + la + ma + "<span class='" + b.toThemeProperty("jqx-tree-grid-title") + ta + "'>" + aa + "</span>";aa = b.rtl ? "<span class='" + b.toThemeProperty("jqx-tree-grid-title") + ta + "'>" + aa + "</span>" + ma + la + ka + ga : ua}if (K > 0 && i && u >= K && M[d.level] < K && (x += "padding-left: 5px; border-left-width: 0px;", Y += "padding-left: 5px; border-left-width: 0px;", aa = "<span style='visibility: hidden;'>-</span>"), x += '" class="' + g + '">', x += aa, x += "</td>", Y += '" class="' + g + '">', Y += aa, Y += "</td>", T.pinned ? (O += x, F += x) : (F += x, E && (O += Y)), K > 0 && !i && M[d.level] < K && !M.aggregate) break}if (0 == f && (b.table[0].style.width = P + 2 + "px", f = P), F += "</tr>", O += "</tr>", A += F, B += O, b.rowDetails && !M.aggregate && this.rowDetailsRenderer) {var va = '<tr data-role="row-details"><td valign="top" align="left" style="pointer-events: auto; max-width:' + w + "px; width:" + w + 'px; overflow: hidden; border-left: none; border-right: none;" colspan="' + b.columns.records.length + '" role="gridcell"',g = b.toTP("jqx-cell") + " " + b.toTP("jqx-grid-cell") + " " + b.toTP("jqx-item");g += " " + b.toTP("jqx-details"),g += " " + b.toTP("jqx-reset");var wa = this.rowDetailsRenderer(N, M);wa && (va += '" class="' + g + '"><div style="pointer-events: auto; overflow: hidden;"><div data-role="details">' + wa + "</div></div></td></tr>", A += va, B += va)}}

  根据笔者层层努力,最终跟踪到代码块中的第112行: 1===S。改成4===S后,刷新页面,果然生效。

图7

但是随之问题又出来了,框架将这个写死了,我们不能将这个写死,因此可以考虑改为可配置方式,此时我们有两个选择,一是修改jqxdatatable.js、二是修改jqxtreegrid.js,考虑到_renderrows属于jqxtreegrid.js,那最终决定在jqxtreegrid.js添加我们的代码:

图8

图9

图10

调用代码

 $("#treeGrid").jqxTreeGrid({source: dataAdapter,hierarchyIconColumnField:'Fresult',columns: [{ text: 'id', dataField: 'Fid', width: 140 ,hidden:true},{ text: '序号', dataField: 'order', width: 50 ,align: 'center'},{ text: '处理人', dataField: 'Foperator', width: 180 ,align: 'center',cellsAlign: 'left',cellsRenderer:function (row, column, value){return '****';}},{ text: '所属环节', dataField: 'Fdepartment', width: 100 ,align: 'center',cellsAlign: 'center'},{ text: '审批结果', dataField: 'Fresult', width: 180, align: 'center', cellsAlign: 'center' },{ text: '上传日期', dataField: 'Ftime', width: 160, align: 'center', cellsAlign: 'center',cellsFormat: "yyyy-MM-dd HH:mm:ss" },{ text: '备注意见', dataField: 'Fopinion', width: 500, align: 'center', cellsAlign: 'center' ,cellsRenderer:function (row, column, value){return '****';}},{ text: '附件名称', dataField: 'Foption_name', width: 300, align: 'center', cellsAlign: 'center' },{ text: '附件类型', dataField: 'Foption_type', width: 160, align: 'center', cellsAlign: 'center'}],ready:function(){$("#treeGrid").jqxTreeGrid('expandAll');},theme:'light',columnsResize:true});

  最终效果:

图11

总结:

JQWidgets实际上仍然有很多不足的地方,但当我们摸清其代码的规律,自己动手去修改其代码且完成达到目的,是一件颇具满足感的事情。

本文主要是根据一个小需求来探索TreeGrid组件、所有的JQWdigets都根据jqxcore.js的applyWidget去分发事件,如果是初始化对象时,则会调用对应组件的createInstance方法。每个JQWdigets组件都有renderer渲染器、如果想要修改控件展示逻辑,则应该深入其代码进行研究。

可能目前的需求只需要该某行代码,而我们只关注这些代码,不去扩展,当以后需求变更或增加时,还得重新回过头来继续研究这些代码的扩展部分,对我们来说,迟早的事情理应要一次性做到位,切忌得过且过

 

转载于:https://www.cnblogs.com/Hxin/p/6861822.html

【原创】JQWidgets-TreeGrid 2、初探源码相关推荐

  1. 源码 状态机_LLVM学习笔记(1)--初探源码

    一直耳闻LLVM相比于GCC: well documented 架构灵活,前后端解耦符合龙书的讲解 昨天读到了一篇虽然概括却很周到的llvm入门导引 陈钦霖:LLVM Pass入门导引​zhuanla ...

  2. [原创]解决某物流企业二维码打印问题

    [原创]解决某物流企业二维码打印问题 参考文章: (1)[原创]解决某物流企业二维码打印问题 (2)https://www.cnblogs.com/ruochen/archive/2012/06/28 ...

  3. 计算机毕业设计Java“原创音乐爱好者”交流网站(源码+系统+mysql数据库+lw文档)

    计算机毕业设计Java"原创音乐爱好者"交流网站(源码+系统+mysql数据库+lw文档) 计算机毕业设计Java"原创音乐爱好者"交流网站(源码+系统+mys ...

  4. 智能AI伪原创工具文章在线生成源码

    ​ 今天我将分享一个更有趣的PHP源码,您可以直接使文章在线伪原创,有需要的朋友可以尝试 它. 所有网站管理员朋友都必须对网站的原始内容感到头疼. 作为草根网站管理员,您不可能自己撰写原创文章. 当然 ...

  5. 【原创】jQuery1.8.2源码解析之jQuery.event

    本片随笔主要是分析了下jQuery的事件模型,即如何统一事件对象,以及处理过程. 这里简要说明一下几点: jQuery通过统一的方法(第62行),eventHandle函数进行事件的分发,利用jQue ...

  6. 550.00 php_16年最新大麦户源码PHP原创自己开发 返800源码绝对运营版shua2016

    普通版: 500 包更新: 1000 源码完全自己开发的,绝对无后门,放心使用,代码只是加了个授权码,自己使用和二次开发都不影响,不能转手卖给其他人,这个代码之前已经运营一年,代码无漏洞,购买后,保证 ...

  7. 原创作者弹幕播放器源码

    介绍: 此播放器接口可用于各大影视cms 只需要上传解压 使用方法 域名/?url= 即可使用本源码开源 无加密 有加密的话全家死光 各位自行拿去研究 setting.js文件全解 网盘下载地址: h ...

  8. php 2016 大麦户源码,16年最新大麦户源码PHP原创自己开发 返800源码绝对运营版shua2016...

    普通版: 500 包更新: 1000 源码完全自己开发的,绝对无后门,放心使用,代码只是加了个授权码,自己使用和二次开发都不影响,不能转手卖给其他人,这个代码之前已经运营一年,代码无漏洞,购买后,保证 ...

  9. 【原创】backbone1.1.0源码解析之Events

    最近在看些node的源代码,发现backbone的应用还是挺广泛的,但是之前的学习忘得一干二净了,后悔当时没做笔记啊. 所以,无奈想用的更好,就是得把源代码看楚,所以还是把源代码的注释笔记留下来,供自 ...

  10. 原创:微信小程序源码解说:石头剪刀布(附源码下载)

    我的博客:来源链接 昨天看有个石头剪刀布的练习,就拿出来做了一下,布局的代码浪费了很多时间,果然CSS这块的还不是很熟练,下面直接上图上代码了. JS: var numAi = 0 var timer ...

最新文章

  1. 想成为优秀的技术人员你必须做到的几件事情
  2. Linux free命令
  3. VTK:IO之ReadPlainTextTriangles
  4. 【轻端重云和边缘架构新模式】
  5. 七桥问题属于计算机科学方法论中的,计算机科学与技术方法论-计算学科中的科学问题ppt...
  6. 隐藏esp_仅需一分钟教你看懂汽车内的隐藏功能,哪些功能是你不知道的?
  7. C++:两种类实例化
  8. onepill服务端
  9. Eclipse快捷键之搜索
  10. linux apache + mysql +php no-yum
  11. JAVA数组——二分查找
  12. IIS DirectoryEntry
  13. 软件开发工程师应该具备哪些证书_初级软件工程师证书简介
  14. ai无法启动计算机丢MSVCP100,win7系统丢失MSVCP100.dll导致程序无法启动的解决方法...
  15. 帝国CMS安全设置大全
  16. Aquatone -- 子域名探测
  17. MySQL基础(一)
  18. 大佬云集的在线少儿英语市场,谁才是那匹冲出重围的黑马?
  19. redis链接不上,报保护模式
  20. 使用CSS3实现流星雨动画教程

热门文章

  1. ios云信不能全屏_网易云信-新增自定义消息(iOS版)
  2. 微服务拆分之道,几条策略和坚持的原则
  3. 基于ARM裸机的知识点总结(9)------基于S5PV210的定时器、看门狗和RTC
  4. 乐理知识以及musicXml属性介绍
  5. Spring3开发实战 之 第二章:IoC/DI开发(2)
  6. 1118 Birds in Forest (25分)——(并查集)
  7. qt多级菜单_Qt高仿电脑管家界面(二):点击按钮弹出菜单
  8. luogu4061 大吉大利,晚上吃鸡!
  9. 【mysql】表锁、行锁、间隙锁、共享锁(读锁)、排他锁(写锁)、Next-Key Locks 之间的关系
  10. 网络工程师学习Linux的亲身历程