• jQuery EasyUI Datagrid组件默认视图分析


      在Datagrid基础DOM结构的一文中,我对Datagrid组件的骨架做了很详细的描述。有了骨架还并不完整,还得有血有肉有衣服穿才行。强大的Datagrid组件允许我们自己定义如何在基础骨架上长出健壮诱人的身体,我们只要定义Datagrid的视图就可以实现。

    在大多数情况下,我们并无特别要求,Datagrid给我们提供了默认的视图,默认视图被使用在90%以上的场景,所以对默认视图的分析显得非常有必要。注意视图里面定义了哪些接口,哪些方法,如果要自己写视图的话,最好把这些接口和方法都写齐全。话不多说,直接上代码(部分注释比较淫荡,未成年人轻绕行)

     
    1. var view = {   
    2.     /**  
    3.      * 填充表格主体数据(生成数据部分的各行tr)  
    4.      * @param  {DOM object} target    datagrid宿主table对应的DOM对象  
    5.      * @param  {DOM object} container 数据主体容器。包含两个可能的值,即:  
    6.      * 1.frozen部分body1,对应的DOM对象为:div.datagrid-view>div.datagrid-view1>div.datagrid-body>div.datagrid-body-inner  
    7.      * 2.常规部分body2,对应的DOM对象为:div.datagrid-view>div.datagrid-view2>div.datagrid-body  
    8.      * @param  {boolean} frozen    是否是冻结列  
    9.      * @return {undefined}           未返回值  
    10.      */  
    11.     render: function(target, container, frozen) {   
    12.         var data = $.data(target, "datagrid");   
    13.         var opts = data.options;   
    14.         var rows = data.data.rows;   
    15.         var fields = $(target).datagrid("getColumnFields", frozen);   
    16.         if(frozen) {   
    17.             //如果grid不显示rownumbers并且也没有frozenColumns的话,直接退出。   
    18.             if(!(opts.rownumbers || (opts.frozenColumns && opts.frozenColumns.length))) {   
    19.                 return;   
    20.             }   
    21.         }   
    22.         //定义表格字符串,注意这里使用了数组的join方式代替了传统的"+"运算符,在大多浏览器中,这样效率会更高些。   
    23.         var html = ["<table class="datagrid-btable" cellspacing="0" cellpadding="0" border="0"><tbody>"];   
    24.         for(var i = 0; i < rows.length; i++) {   
    25.             //striped属性,用于设置grid数据是否隔行变色,当然了实现原理很简单。   
    26.             var cls = (i % 2 && opts.striped) ? "class="datagrid-row datagrid-row-alt"" : "class="datagrid-row"";   
    27.             /**  
    28.              * 表格的rowStyler属性用于处理数据行的css样式,当然了这个样式仅仅是作用于tr标签上。  
    29.              * 这地方使用call了方法来设置上下文,如果rowStyler函数内部使用了this的话,则this指向datagrid的宿主table对应的DOM对象。  
    30.              */  
    31.             var style = opts.rowStyler ? opts.rowStyler.call(target, i, rows[i]) : "";   
    32.             var styler = style ? "style="" + style + """ : "";   
    33.             /**  
    34.              * rowId:行的唯一标示,对应于tr的id属性,其由以下几部分组成:  
    35.              * 1.字符窜常量:"datagrid-row-r";  
    36.              * 2.全局索引index:该索引值从1开始递增,同一个datagrid组件实例拥有唯一值,如果同一页面内有多个datagrid实例,那么其值从1递增分配给每个datagrid实例;  
    37.              * 3.冻结列标识frozen:该标识用于标示是否是冻结列(包含行号和用户指定的frozenColumns),"1"代表冻结列,"2"代表非冻结列;  
    38.              * 4.行数索引:该值才是真正代表“第几行”的意思,该值从0开始递增  
    39.              * 如页面内第一个datagrid实例的非冻结列第10行数据的rowId为"datagrid-row-r1-2-9"  
    40.              */  
    41.             var rowId = data.rowIdPrefix + "-" + (frozen ? 1 : 2) + "-" + i;   
    42.             html.push("<tr id="" + rowId + "" datagrid-row-index="" + i + "" " + cls + " " + styler + ">");   
    43.             /**  
    44.              * 调用renderRow方法,生成行数据(行内的各列数据)。  
    45.              * 这里的this就是opts.view,之所以用call方法,只是为了传参进去。这里我们使用this.renderRow(target,fields,frozen,i,rows[i])来调用renderRow方法应该也是可以的。  
    46.              */  
    47.             html.push(this.renderRow.call(this, target, fields, frozen, i, rows[i]));   
    48.             html.push("</tr>");   
    49.         }   
    50.         html.push("</tbody></table>");   
    51.         //用join方法完成字符创拼接后直接innerHTML到容器内。   
    52.         $(container).html(html.join(""));   
    53.     },   
    54.     /**  
    55.      * [renderFooter   description]  
    56.      * @param  {DOM object} target   datagrid宿主table对应的DOM对象  
    57.      * @param  {DOM object} container 可能为dc.footer1或者dc.footer2  
    58.      * @param  {boolean} frozen    是否为frozen区  
    59.      * @return {undefined}           未返回值  
    60.      */  
    61.     renderFooter: function(target, container, frozen) {   
    62.         var opts = $.data(target, "datagrid").options;   
    63.         //获取footer数据   
    64.         var rows = $.data(target, "datagrid").footer || [];   
    65.         var columnsFields = $(target).datagrid("getColumnFields", frozen);   
    66.         //生成footer区的table   
    67.         var footerTable = ["<table class="datagrid-ftable" cellspacing="0" cellpadding="0" border="0"><tbody>"];   
    68.         for(var i = 0; i < rows.length; i++) {   
    69.             footerTable.push("<tr class="datagrid-row" datagrid-row-index="" + i + "">");   
    70.             footerTable.push(this.renderRow.call(this, target, columnsFields, frozen, i, rows[i]));   
    71.             footerTable.push("</tr>");   
    72.         }   
    73.         footerTable.push("</tbody></table>");   
    74.         $(container).html(footerTable.join(""));   
    75.     },   
    76.     /**  
    77.      * 生成某一行数据  
    78.      * @param  {DOM object} target   datagrid宿主table对应的DOM对象  
    79.      * @param  {array} fields   datagrid的字段列表  
    80.      * @param  {boolean} frozen   是否为冻结列  
    81.      * @param  {number} rowIndex 行索引(从0开始)  
    82.      * @param  {json object} rowData  某一行的数据  
    83.      * @return {string}          单元格的拼接字符串  
    84.      */  
    85.     renderRow: function(target, fields, frozen, rowIndex, rowData) {   
    86.         var opts = $.data(target, "datagrid").options;   
    87.         //用于拼接字符串的数组   
    88.         var cc = [];   
    89.         if(frozen && opts.rownumbers) {   
    90.             //rowIndex从0开始,而行号显示的时候是从1开始,所以这里要加1.   
    91.             var rowNumber = rowIndex + 1;   
    92.             //如果分页的话,根据页码和每页记录数重新设置行号   
    93.             if(opts.pagination) {   
    94.                 rowNumber += (opts.pageNumber - 1) * opts.pageSize;   
    95.             }   
    96.             /**  
    97.              * 先拼接行号列  
    98.              * 注意DOM特征,用zenCoding可表达为"td.datagrid-td-rownumber>div.datagrid-cell-rownumber"  
    99.              */  
    100.             cc.push("<td class="datagrid-td-rownumber"><div class="datagrid-cell-rownumber">" + rowNumber + "</div></td>");   
    101.         }   
    102.         for(var i = 0; i < fields.length; i++) {   
    103.             var field = fields[i];   
    104.             var col = $(target).datagrid("getColumnOption", field);   
    105.             if(col) {   
    106.                 var value = rowData[field];   
    107.                 //获取用户定义的单元格样式,入参包括:单元格值,当前行数据,当前行索引(从0开始)   
    108.                 var style = col.styler ? (col.styler(value, rowData, rowIndex) || "") : "";   
    109.                 //如果是隐藏列直接设置display为none,否则设置为用户想要的样式   
    110.                 var styler = col.hidden ? "style="display:none;" + style + """ : (style ? "style="" + style + """ : "");   
    111.                 cc.push("<td field="" + field + "" " + styler + ">");   
    112.                 //如果当前列是datagrid组件保留的ck列时,则忽略掉用户定义的样式,即styler属性对datagrid自带的ck列是不起作用的。   
    113.                 if(col.checkbox) {   
    114.                     var styler = "";   
    115.                 } else {   
    116.                     var styler = "";   
    117.                     //设置文字对齐属性   
    118.                     if(col.align) {   
    119.                         styler += "text-align:" + col.align + ";";   
    120.                     }   
    121.                     //设置文字超出td宽时是否自动换行(设置为自动换行的话会撑高单元格)   
    122.                     if(!opts.nowrap) {   
    123.                         styler += "white-space:normal;height:auto;";   
    124.                     } else {   
    125.                         /**  
    126.                          * 并不是nowrap属性为true单元格就肯定不会被撑高,这还得看autoRowHeight属性的脸色  
    127.                          * 当autoRowHeight属性为true的时候单元格的高度是根据单元格内容而定的,这种情况主要是用于表格里展示图片等媒体。  
    128.                          */  
    129.                         if(opts.autoRowHeight) {   
    130.                             styler += "height:auto;";   
    131.                         }   
    132.                     }   
    133.                 }   
    134.                 //这个地方要特别注意,前面所拼接的styler属性并不是作用于td标签上,而是作用于td下的div标签上。   
    135.                 cc.push("<div style="" + styler + "" ");   
    136.                 //如果是ck列,增加"datagrid-cell-check"样式类   
    137.                 if(col.checkbox) {   
    138.                     cc.push("class="datagrid-cell-check ");   
    139.                 }   
    140.                 //如果是普通列,增加"datagrid-cell-check"样式类   
    141.                 else {   
    142.                     cc.push("class="datagrid-cell " + col.cellClass);   
    143.                 }   
    144.                 cc.push("">");   
    145.                 /**  
    146.                  * ck列光设置class是不够的,当突然还得append一个input进去才是真正的checkbox。此处未设置input的id,只设置了name属性。  
    147.                  * 我们注意到formatter属性对datagird自带的ck列同样不起作用。  
    148.                  */  
    149.                 if(col.checkbox) {   
    150.                     cc.push("<input type="checkbox" name="" + field + "" value="" + (value != undefined ? value : "") + ""/>");   
    151.                 }   
    152.                 //普通列   
    153.                 else {   
    154.                     /**  
    155.                      * 如果单元格有formatter,则将formatter后生成的DOM放到td>div里面  
    156.                      * 换句话说,td>div就是如来佛祖的五指山,而formatter只是孙猴子而已,猴子再怎么变化翻跟头,始终在佛祖手里。  
    157.                      */  
    158.                     if(col.formatter) {   
    159.                         cc.push(col.formatter(value, rowData, rowIndex));   
    160.                     }   
    161.                     //操,这是最简单的简况了,将值直接放到td>div里面。   
    162.                     else {   
    163.                         cc.push(value);   
    164.                     }   
    165.                 }   
    166.                 cc.push("</div>");   
    167.                 cc.push("</td>");   
    168.             }   
    169.         }   
    170.         //返回单元格字符串,注意这个函数内部并未把字符串放到文档流中。   
    171.         return cc.join("");   
    172.     },   
    173.     /**  
    174.      * 刷新行数据,只有一个行索引(从0开始),调用的updateRow方法,这里直接跳过。  
    175.      * @param  {DOM object} target   datagrid实例的宿主table对应的DOM对象  
    176.      * @param  {number} rowIndex 行索引(从0开始)  
    177.      * @return {undefined}          未返回数据  
    178.      */  
    179.     refreshRow: function(target, rowIndex) {   
    180.         this.updateRow.call(this, target, rowIndex, {});   
    181.     },   
    182.     /**  
    183.      * 刷新行数据,该接口方法肩负着同步行高,重新计算和布局grid面板等重任  
    184.      * @param  {DOM object} target   datagrid实例的宿主table对应的DOM对象  
    185.      * @param  {number} rowIndex 行索引(从0开始)  
    186.      * @param  {json object} 行数据  
    187.      * @return {undefined}          未返回数据  
    188.      */  
    189.     updateRow: function(target, rowIndex, row) {   
    190.         var opts = $.data(target, "datagrid").options;   
    191.         var rows = $(target).datagrid("getRows");   
    192.         $.extend(rows[rowIndex], row);   
    193.         var style = opts.rowStyler ? opts.rowStyler.call(target, rowIndex, rows[rowIndex]) : "";   
    194.   
    195.         function updateTableRow(frozen) {   
    196.             var fields = $(target).datagrid("getColumnFields", frozen);   
    197.             //这个地方查找grid的数据主体表格(可能包含冻结列对应的主体表格和普通列对应的主体表格)   
    198.             //getTr这个函数,我在博客上介绍过,请参考:http://www.easyui.info/archives/396.html   
    199.             var tr = opts.finder.getTr(target, rowIndex, "body", (frozen ? 1 : 2));   
    200.             var checked = tr.find("div.datagrid-cell-check input[type=checkbox]").is(":checked");   
    201.             //这里调用了renderRow方法来重新获取当前行的html字符串   
    202.             tr.html(this.renderRow.call(this, target, fields, frozen, rowIndex, rows[rowIndex]));   
    203.             tr.attr("style", style || "");   
    204.             //更新的时候保留checkbox状态(包含两层信息:一是有ck列;二是ck列被之前就被选中)   
    205.             if(checked) {   
    206.                 tr.find("div.datagrid-cell-check input[type=checkbox]")._propAttr("checked"true);   
    207.             }   
    208.         };   
    209.         //更新冻结列对应的行   
    210.         updateTableRow.call(thistrue);   
    211.         //更新普通列对应的行   
    212.         updateTableRow.call(thisfalse);   
    213.         //重新布局表格面板   
    214.         $(target).datagrid("fixRowHeight", rowIndex);   
    215.     },   
    216.     insertRow: function(target, rowIndex, row) {   
    217.         var state = $.data(target, "datagrid");   
    218.         //options   
    219.         var opts = state.options;   
    220.         //document of datagrid   
    221.         var dc = state.dc;   
    222.         var data = state.data;   
    223.         //兼容无效的rowIndex,默认设置为在最后一行追加   
    224.         if(rowIndex == undefined || rowIndex == null) {   
    225.             rowIndex = data.rows.length;   
    226.         }   
    227.         //为啥不跟上面的条件并到一起,真是蛋疼   
    228.         if(rowIndex > data.rows.length) {   
    229.             rowIndex = data.rows.length;   
    230.         }   
    231.         /**  
    232.          * 下移rows  
    233.          * @param  {boolean} frozen 是否为frozen部分  
    234.          * @return {undefined}        无返回值  
    235.          */  
    236.         function moveDownRows(frozen) {   
    237.             //1:冻结列部分;2:普通列部分   
    238.             var whichBody = frozen ? 1 : 2;   
    239.             for(var i = data.rows.length - 1; i >= rowIndex; i--) {   
    240.                 var tr = opts.finder.getTr(target, i, "body", whichBody);   
    241.                 //注意这地方设置了tr的"datagrid-row-index"和"id"属性   
    242.                 tr.attr("datagrid-row-index", i + 1);   
    243.                 tr.attr("id", state.rowIdPrefix + "-" + whichBody + "-" + (i + 1));   
    244.                 //计算行号   
    245.                 if(frozen && opts.rownumbers) {   
    246.                     //因rowIndex从0开始,以及须插入位置以下的tr要统一下移,所以新行号为i+2   
    247.                     var rownumber = i + 2;   
    248.                     //有分页的话,行号还要加上分页数据   
    249.                     if(opts.pagination) {   
    250.                         rownumber += (opts.pageNumber - 1) * opts.pageSize;   
    251.                     }   
    252.                     tr.find("div.datagrid-cell-rownumber").html(rownumber);   
    253.                 }   
    254.             }   
    255.         };   
    256.         /**  
    257.          * 插入了,要插两个地方的哦(如果你是男人,你可以淫荡地笑一下)  
    258.          * @param  {boolean} frozen 是否是frozen部分  
    259.          * @return {undefined}        未返回值  
    260.          */  
    261.         function doInsert(frozen) {   
    262.             var whichBody = frozen ? 1 : 2;   
    263.             //这行代码,不知道是干嘛的,怕插入得太快而早早缴械,所以才故意拖延时间的么?   
    264.             var columnFields = $(target).datagrid("getColumnFields", frozen);   
    265.             //构造新插入行的id属性   
    266.             var trId = state.rowIdPrefix + "-" + whichBody + "-" + rowIndex;   
    267.             var tr = "<tr id="" + trId + "" class="datagrid-row" datagrid-row-index="" + rowIndex + ""></tr>";   
    268.             if(rowIndex >= data.rows.length) {   
    269.                 //如果已经有记录,则插入tr即可   
    270.                 if(data.rows.length) {   
    271.                     //嗯哼,getTr的这个用法不多哦,未传入行索引,第三个参数为"last",随便的意淫一下就知道是获取最后一行了   
    272.                     //然后再在最后一行后插入一行,注意了,这里用的后入式   
    273.                     opts.finder.getTr(target, """last", whichBody).after(tr);   
    274.                 }   
    275.                 //如果表格尚无记录,则要生成表格,同时插入tr   
    276.                 else {   
    277.                     var cc = frozen ? dc.body1 : dc.body2;   
    278.                     cc.html("<table cellspacing="0" cellpadding="0" border="0"><tbody>" + tr + "</tbody></table>");   
    279.                 }   
    280.             }   
    281.             //在rowIndex + 1前准确无误地插入,注意了,这里是前入式。   
    282.             else {   
    283.                 opts.finder.getTr(target, rowIndex + 1, "body", whichBody).before(tr);   
    284.             }   
    285.         };   
    286.         //下移frozen部分   
    287.         moveDownRows.call(thistrue);   
    288.         //下移普通列部分   
    289.         moveDownRows.call(thisfalse);   
    290.         //插入frozen区   
    291.         doInsert.call(thistrue);   
    292.         //插入普通区   
    293.         doInsert.call(thisfalse);   
    294.         //总数加1   
    295.         data.total += 1;   
    296.         //维护data.rows数组,这地方是插入一个数组元素了   
    297.         data.rows.splice(rowIndex, 0, row);   
    298.         //刷新,其中包含了重新布局grid面板等复杂得一笔的操作   
    299.         //插入本是件很简单愉快的事情,可是你得为其后果负上沉重的代价   
    300.         this.refreshRow.call(this, target, rowIndex);   
    301.     },   
    302.     /**  
    303.      * 删除行接口  
    304.      * @param  {DOM object} target datagrid实例的宿主table对应的DOM对象  
    305.      * @param  {number} rowIndex 行索引  
    306.      * @return {undefined}        未返回值  
    307.      */  
    308.     deleteRow: function(target, rowIndex) {   
    309.         var state = $.data(target, "datagrid");   
    310.         var opts = state.options;   
    311.         var data = state.data;   
    312.   
    313.         function moveUpRows(frozen) {   
    314.             var whichBody = frozen ? 1 : 2;   
    315.             for(var i = rowIndex + 1; i < data.rows.length; i++) {   
    316.                 var tr = opts.finder.getTr(target, i, "body", whichBody);   
    317.                 //"datagrid-row-index"和"id"属性减一   
    318.                 tr.attr("datagrid-row-index", i - 1);   
    319.                 tr.attr("id", state.rowIdPrefix + "-" + whichBody + "-" + (i - 1));   
    320.                 if(frozen && opts.rownumbers) {   
    321.                     var rownumber = i;   
    322.                     if(opts.pagination) {   
    323.                         rownumber += (opts.pageNumber - 1) * opts.pageSize;   
    324.                     }   
    325.                     tr.find("div.datagrid-cell-rownumber").html(rownumber);   
    326.                 }   
    327.             }   
    328.         };   
    329.         //移除行   
    330.         opts.finder.getTr(target, rowIndex).remove();   
    331.         //上移frozen区   
    332.         moveUpRows.call(thistrue);   
    333.         //上移普通区   
    334.         moveUpRows.call(thisfalse);   
    335.         //记录数减一   
    336.         data.total -= 1;   
    337.         //维护data.rows数据   
    338.         data.rows.splice(rowIndex, 1);   
    339.     },   
    340.     /**  
    341.      * 默认的onBeforeRender事件 为空  
    342.      * @param  {DOM object} target datagrid实例的宿主table对应的DOM对象  
    343.      * @param  {array} rows 要插入的数据  
    344.      * @return {undefined}        默认未返回值  
    345.      */  
    346.     onBeforeRender: function(target, rows) {},   
    347.     /**  
    348.      * 默认的onAfterRender 隐藏footer里的行号和check  
    349.      * @param  {DOM object} target datagrid实例的宿主table对应的DOM对象  
    350.      * @return {undefined}        未返回值  
    351.      */  
    352.     onAfterRender: function(target) {   
    353.         var opts = $.data(target, "datagrid").options;   
    354.         if(opts.showFooter) {   
    355.             var footer = $(target).datagrid("getPanel").find("div.datagrid-footer");   
    356.             footer.find("div.datagrid-cell-rownumber,div.datagrid-cell-check").css("visibility""hidden");   
    357.         }   
    358.     }   
    359. };  
     
    ******转载:http://www.easyui.info/archives/1196.html
  • 相关阅读:
    COM学习(三)——数据类型
    com学习(一)GUID 和 接口
    Dll学习(二)__declspec用法详解
    dll 学习(一)
    PostMessage与SendMessage的区别(二)
    sendmessage和postmessage的区别
    用Java开发代理服务器
    JAVA编写WEB服务器
    【1.3】Django HelloWorld
    【1.2】初识Django应用
  • 原文地址:https://www.cnblogs.com/linybo/p/10054089.html
Copyright © 2020-2023  润新知