Skip to content

Grid 表格

WebBuilder Grid 的样式、合计、编辑、分页与交互用法。

Updated View as Markdown

表格背景颜色

image-20210104093045038

//在viewConfig 的 getRowClass中
//Wb预定义行背景色种类:wb_red_row, wb_green_row, wb_blue_row, wb_yellow_row, wb_hotpink_row, wb_gold_row, wb_bisque_row, wb_aqua_row
var cls, finalMoney = record.get('FINAL_MONEY');
if (finalMoney == '0'||finalMoney==null)
  cls = '';
else 
  cls = '';
return cls;

表格中文字格式

//initialize中加入
Ext.util.CSS.createStyleSheet(".font_red{color:red}","font_red");

//如果是grid表格的背景
Ext.util.CSS.createStyleSheet(".xxx .x-grid-cell {background-color: red}","xxx");

//在viewConfig 的 getRowClass中
//Wb预定义行背景色种类:wb_red_row, wb_green_row, wb_blue_row, wb_yellow_row, wb_hotpink_row, wb_gold_row, wb_bisque_row, wb_aqua_row
var cls, finalMoney = record.get('FINAL_MONEY');
if (finalMoney == '0'||finalMoney==null)
  cls = '';
else 
  cls = '';
return cls;

表格合计

image-20210104093045038

image-20210104093353913

image-20210104093427024

// features 中放入feature
// feature 中的 ftype 设置分别表示统计和分组统计
//summaryRenderer代表最终输出的格式 可改变 字体和背景
//summaryType可选 求和 平均等

选中合计

grid/bottomHtml

<lable id='underDiv' style = 'margin-left:330px;font-weight:bold;'></lable>

tagEvent

{
  select: function(editor, e, eOpts) { //e是要选中的行
    var resc = app.unRcvGrid.getSelection();
    showTotal(resc, "unGridDiv222");
  },
  deselect: function(editor, e, eOpts) { //e是取消的行
    var resc = app.unRcvGrid.getSelection();
    showTotal(resc, "unGridDiv222");
  }
}
function showTotal(recs, divId){
  var usd = 0, cny = 0;
  Wb.each(recs, function(one) {
    if (one.data.CURRENCY === 'USD') { //美元合计
      usd += one.data.MONEY;
    }
    if (one.data.CURRENCY === 'CNY') { //人民币合计
      cny += one.data.MONEY;
    }
  });
  var context = '选中合计:';
  context += "&nbsp; CNY:<font color='red'>" + Wb.format(cny, '0,000.00')+"</font>";  
  context += "&nbsp;&nbsp; USD:<font color='red'>" + Wb.format(usd, '0,000.00')+"</font>";
  document.getElementById(divId).innerHTML = context;
}

表格分组

image-20210204171639545

image-20210204171716331

image-20210204171726858

可编辑表格判断某行某一列修改没修改

var recsm = Wb.getModified(app.gridContract);
var flag = 0;
Wb.each(recsm.update, function(one) {
  if (!Wb.isEmpty(one.APPLYTIM)) {
    if (!Wb.isEmpty(one.RELEASE_NO) && one.RELEASE_NO != one["#RELEASE_NO"]) {
      //修改了外放箱号,可执行
    } else {
      flag = 1;
    }
  }
});

可编辑式表格控制符合某种条件的行不可编辑

在 grid 的 tagEvents 事件中添加如下代码,判断条件以实际情况而定

{
  beforeedit: function(editor, e, eOpts) {
   if(e.record.data.AC_CODE=='CNH004502'){
   	return false;//不可编辑
   }else{
   	return true;//可以编辑
   }
  }
}

为某一列添加背景色

在该列的renderer方法里设置

metaData.style='background-color:#fff;';
return '<span style="color:#f00">'+value+'</span>';//修改字的颜色

为表格中单元格添加点击事件

增加事件

//首先在we_debug.js中添加以下方法
columnClick:function(view,e,columnname,func){
   var column = view.getHeaderByCell(e.getTarget(view.getCellSelector()));
   if(column && column.dataIndex == columnname){
      func();
   }
},
//grid的itemclick事件添加以下代码
Wb.columnClick(view,e,"CARGO_NAM",function(){
  if(!Wb.isEmpty(record.data.SHIP_CARGO_NO))
    return;
  Wb.reset(app.winTrust);
  app.winTrust.show();
  ...//方法处理
});

使用actioncolumn

//handler中写入点击后执行函数
setTimeout(function() {
  app.sealWin.show();
  var id = record.data.ID;
  app.sealGrid.store.load({
    params: {
      cntrId: id
    }
  });
}, 100);

鼠标悬浮某单元格时显示全部信息

//在某列column的renerder属性添加以下代码
metaData.tdAttr = 'data-qtip="' + Ext.String.htmlEncode(value) + '"'; //给每一个Cell添加tooltip效果
return value;

大数据虚拟渲染

bufferedrenderer 是 Ext Grid 的虚拟行渲染插件。它只创建当前可视区域及前后缓冲区的行 DOM;滚动时复用和更新这些行,而不是为每条记录同时创建页面元素。

适用于固定或基本固定行高的普通表格。行展开、频繁变化的自动换行行高、复杂合并单元格等场景可能影响滚动定位,应单独验证。

本地数据测试

插件配置加在 Grid 上,fields 配置加在 Grid 下的 Store 上。下面模块点击 check 后一次写入 10 万条记录,用于验证表格的渲染和滚动性能。

module = {
  itemId: "module",
  items: [{
    itemId: "viewport1",
    layout: "fit",
    items: [{
      itemId: "grid1",
      pagingBar: false,
      plugins: {
        ptype: "bufferedrenderer",
        leadingBufferZone: 200,
        trailingBufferZone: 100
      },
      items: [{
        itemId: "tbar",
        items: [{
          iconCls: "accept_icon",
          itemId: "item1",
          text: "check",
          events: {
            click: function(item) {
              var store = item.up("grid").store;
              var rows = new Array(100000);
              var i;

              for (i = 0; i < 100000; i++) {
                rows[i] = {
                  ID: i + 1,
                  SEX: i % 2 === 0 ? "男" : "女"
                };
              }

              store.loadData(rows, false);
            }
          }
        }]
      }, {
        itemId: "store",
        fields: ["ID", "SEX"]
      }, {
        itemId: "columns",
        items: [{
          dataIndex: "ID",
          itemId: "IDCol",
          text: "主键",
          width: 120
        }, {
          dataIndex: "SEX",
          itemId: "SEXCol",
          text: "性别",
          width: 100
        }]
      }]
    }]
  }]
};

不要在循环中执行 store.add()。每次调用都会触发 Store 和 Grid 的更新;先构建数组,再执行一次 store.loadData(rows, false) 才是用于批量测试和导入的合适方式。

此例仍会将 10 万条 Model 保留在浏览器内存中,只是避免创建 10 万行 DOM。因此它用于验证渲染性能,不是生产环境加载海量数据的最终方案。

URL 数据源

对于生产数据,将分页、排序和筛选交由服务端处理。Grid 继续配置 bufferedrenderer,并在 Store 上启用缓冲加载:

{
  itemId: "grid1",
  pagingBar: false,
  plugins: {
    ptype: "bufferedrenderer",
    leadingBufferZone: 200,
    trailingBufferZone: 100
  },
  items: [{
    itemId: "store",
    url: "m?xwl=demo/order/query",
    fields: ["ID", "SEX"],
    buffered: true,
    pageSize: 100,
    purgePageCount: 5,
    remoteSort: true,
    remoteFilter: true
  }]
}

Store 会以 startlimit 请求数据。服务端必须使用这两个参数分页查询,并在响应中提供当前页记录和总记录数。例如:

{
  "data": [
    { "ID": 1, "SEX": "男" }
  ],
  "total": 100000
}

若接口仍一次返回全部记录,不要配置 buffered: true;仅使用 Grid 插件即可减少 DOM 数量。启用 buffered: true 前,也要确认当前 Ext Store Reader 的记录数组字段和总数字段名称与接口响应一致。

参数建议

配置 建议值 作用
pageSize 100 每次从服务端读取的记录数。可根据单行数据大小在 50 到 200 间调整。
leadingBufferZone 200 当前视口之后预先渲染的行数,降低向下滚动时的空白感。
trailingBufferZone 100 当前视口之前保留的行数,改善向上回滚。
purgePageCount 5 Store 缓存的页数,限制客户端内存占用。

不要同时使用传统分页栏和缓冲滚动作为同一张 Grid 的主导航方式。前者适合可明确跳页的业务表格,后者适合持续浏览大量记录的场景。

grid数据以数组形式传参到wb数据层

//参数获取
cntrsdata: app.gridReceipt.store.data.items.map(function(r) {
   return r.data;
})

//wb数据层接收示例
cntrsdata = Wb.decode(data.cntrsdata); //grid数据

给表格某行某列赋值

var rec = app.workloadGrid.getSelection()[0];//获取当前选中的行
rec.set('PROJECT_NAME',"sssss");//给该行某一列赋值

动态选中表格行

app.gridxxx.getSelectionModel().select(records[0]);//选中第一行

var index = app.gridxxx.store.find("ID","123");//选中ID为123的行
app.gridxxx.getSelectionModel().select(index);//选中第一行

//选中某些符合条件的行
Wb.request({
    url: 'm?xwl=imtos/basecode/C_Client/selectTypeByClientType',
    params: {
     ID:clientId
    },
    success: function(resp) {
      var respArr = JSON.parse(resp.responseText).rows;  
      var roleRec, selRecs = [];
      console.log(respArr);
      Wb.each(respArr, function(rec) {
        roleRec = Wb.find(app.gridmessage.store, 'TYPE_CODE', rec.CLIENT_TYPE_CODE);
        if (roleRec)
          selRecs.push(roleRec);
      });
      app.gridmessage.setSelection(selRecs);
    }
  });

表格内容竖向展示

//在需要竖向展示的列的render方法中添加以下代码
return '<div style="writing-mode:tb-rl">'+value+'</div>'

表格前加复选框多选时,禁止点击单元格(数据行)选择,只能点击复选框选择

//在grid的selModel属性中添加以下代码
new Ext.selection.CheckboxModel({ checkOnly: true })

合并行

img

mergeGrid(app.gridFee, [2,3,4], true);//列标从0开始
/**
 * 合并Grid的数据列
 * @param grid {Ext.Grid.Panel} 需要合并的Grid
 * @param colIndexArray {Array} 需要合并列的Index(序号)数组;从0开始计数,序号也包含。
 * @param isAllSome {Boolean} 是否2个tr的colIndexArray必须完成一样才能进行合并。true:完成一样;false:不完全一样
 */
function mergeGrid(grid, colIndexArray, isAllSome) {
  isAllSome = isAllSome == undefined ? true : isAllSome; // 默认为true
  // 1.是否含有数据
  var gridView = document.getElementById(grid.getView().getId() + '-body');
  if (gridView == null) {
    return;
  }
  // 2.获取Grid的所有tr
  var trArray = [];
  if (grid.layout.type == 'table') { // 若是table部署方式,获取的tr方式如下
    trArray = gridView.childNodes;
  } else {
    trArray = gridView.getElementsByTagName('tr');
  }
  // 3.进行合并操作
  if (isAllSome) { // 3.1 全部列合并:只有相邻tr所指定的td都相同才会进行合并
    var lastTr = trArray[0]; // 指向第一行
    // 1)遍历grid的tr,从第二个数据行开始
    for (var i = 1, trLength = trArray.length; i < trLength; i++) {
      var thisTr = trArray[i];
      var isPass = true; // 是否验证通过
      // 2)遍历需要合并的列
      for (var j = 0, colArrayLength = colIndexArray.length; j < colArrayLength; j++) {
        var colIndex = colIndexArray[j];
        // 3)比较2个td的列是否匹配,若不匹配,就把last指向当前列
       // console.info(lastTr.childNodes[colIndex].innerText);
       // console.info(thisTr.childNodes[colIndex].innerText);
        if(colIndex != 11 && colIndex != 16){
          if (lastTr.childNodes[colIndex].innerText != thisTr.childNodes[colIndex].innerText) {
            lastTr = thisTr;
            isPass = false;
            break;
          }
        }
      }
      // 4)若colIndexArray验证通过,就把当前行合并到'合并行'
      if (isPass) {
        for (var j = 0, colArrayLength = colIndexArray.length; j < colArrayLength; j++) {
          var colIndex = colIndexArray[j];
          
            // 5)设置合并行的td rowspan属性
            if (lastTr.childNodes[colIndex].hasAttribute('rowspan')) {
              var rowspan = lastTr.childNodes[colIndex].getAttribute('rowspan') - 0;
              rowspan++;
              lastTr.childNodes[colIndex].setAttribute('rowspan', rowspan);
            } else {
              lastTr.childNodes[colIndex].setAttribute('rowspan', '2');
            }
            // lastTr.childNodes[colIndex].style['text-align'] = 'center';; // 水平居中
            lastTr.childNodes[colIndex].style['vertical-align'] = 'middle'; // 纵向居中
            //lastTr.childNodes[colIndex].style['vertical-align'] = 'top'; // 纵向居中
            thisTr.childNodes[colIndex].style.display = 'none';
         
        }
      }
    }
  } else { // 3.2 逐个列合并:每个列在前面列合并的前提下可分别合并
    // 1)遍历列的序号数组
    for (var i = 0, colArrayLength = colIndexArray.length; i < colArrayLength; i++) {
      var colIndex = colIndexArray[i];
      var lastTr = trArray[0]; // 合并tr,默认为第一行数据
      // 2)遍历grid的tr,从第二个数据行开始
      for (var j = 1, trLength = trArray.length; j < trLength; j++) {
        var thisTr = trArray[j];
        // 3)2个tr的td内容一样
        if (lastTr.childNodes[colIndex].innerText == thisTr.childNodes[colIndex].innerText) {
          // 4)若前面的td未合并,后面的td都不进行合并操作
          if (i > 0 && thisTr.childNodes[colIndexArray[i - 1]].style.display != 'none') {
            lastTr = thisTr;
            continue;
          } else {
            // 5)符合条件合并td
            if (lastTr.childNodes[colIndex].hasAttribute('rowspan')) {
              var rowspan = lastTr.childNodes[colIndex].getAttribute('rowspan') - 0;
              rowspan++;
              lastTr.childNodes[colIndex].setAttribute('rowspan', rowspan);
            } else {
              lastTr.childNodes[colIndex].setAttribute('rowspan', '2');
            }
            //lastTr.childNodes[colIndex].style['text-align'] = 'center'; // 水平居中
            lastTr.childNodes[colIndex].style['vertical-align'] = 'middle'; // 纵向居中
            thisTr.childNodes[colIndex].style.display = 'none'; // 当前行隐藏
          }
        } else {
          // 5)2个tr的td内容不一样
          lastTr = thisTr;
        }
      }
    }
  }
}

表格列展示位复选框形式

img

//tagConfigs属性添加以下代码
{
  getValue: function() {
    if (this.value==true||this.value=='1') {
      return 1;
    } else {
      return 0;
    }
  }
}
//该列 字段查询语句要做转数字:to_number(HIRE_FLAG,'9')  HIRE_FLAG

符合条件的行禁止选中

image-20210114171539198

if(record.data.DELIVERY_FLAG !='1'&&record.data.DELIVERY_FLAG !=1){
  return true;
}else{
  return false;
}

表格后台分页

image-20210114171706986

image-20210114171805821

SELECT * FROM (
   SELECT ROWNUM AS rowno, t.* 
   FROM emp t 
   WHERE hire_date BETWEEN TO_DATE ('20060501', 'yyyymmdd') 
   AND TO_DATE ('20060731', 'yyyymmdd') 
   AND ROWNUM <= {?bigint.endIndex?}) table_alias 
WHERE table_alias.rowno >= {?bigint.beginIndex?};

分组合计小计

(1)gird增加合计和分组合计控件

img

groupingsummary属性配置如下,summary为常规配置

img

(2)页面区别“合计”和“小计”字眼

image-20210114172321954

var re = summaryData._featureObject instanceof Ext.grid.feature.Summary ? '合计:' : '小计:';
return "<span style='font-weight:bold;'>" + re + "</span>";

(3)按某个属性合计显示,该实例中是以箱尺寸分类显示

//在需要显示的列的summaryRenderer中添加代码
/**
 * 合计小计按尺寸自定义显示。
 */
var cntr20 = 0,
  cntr40 = 0;
if (summaryData._featureObject instanceof Ext.grid.feature.GroupingSummary) { //小计
  if (summaryData.CNTR_NUM > 0) {
    app.coutStore.each(function(rec) {
      if (rec.data.CNTR_NUM > 0) {
        if (rec.data.SIZE_CODE === '20') {
          cntr20 += rec.data.CNTR_NUM;
        } else if (rec.data.SIZE_CODE === '40') {
          cntr40 += rec.data.CNTR_NUM;
        }
      }
    });
  } else if (summaryData.CNTR_NUM < 0) {
    app.coutStore.each(function(rec) {
      if (rec.data.CNTR_NUM < 0) {
        if (rec.data.SIZE_CODE === '20') {
          cntr20 += rec.data.CNTR_NUM;
        } else if (rec.data.SIZE_CODE === '40') {
          cntr40 += rec.data.CNTR_NUM;
        }
      }
    });
  }
} else if (summaryData._featureObject instanceof Ext.grid.feature.Summary) { //合计
  app.coutStore.each(function(rec) {
    if (rec.data.SIZE_CODE === '20') {
      cntr20 += rec.data.CNTR_NUM;
    } else if (rec.data.SIZE_CODE === '40') {
      cntr40 += rec.data.CNTR_NUM;
    }
  });
}

return Wb.format("<span style='font-weight:bold;'>" + cntr20 + "<br>" + cntr40 + "<br>{0}</span>", value);

满足条件才可进行编辑表格

grid /tagEvent

beforeedit: function(editor, e, eOpts) {
    //条件
  var condition = e.record.data.xxx;
    //控制的字段
  var field = e.field;
  if(e.field==""&&condition=""){
    return false;
  }else{
    return true;
  }
}

对单元格中的action进行隐藏

if (record.get('SEX') !=2) {
  return 'x-hidden';
} else {
  return '';
}

隐藏某一列数据

app.xxgrid.down('#BILL_NOCol').hide()

grid上单元格的悬浮显示

//
function showTip(data, metadata, record_start, rowindex, columnindex, store) {
  if (!Wb.isEmpty(data)) { // 此处对空白文本做过滤。
    metadata.tdAttr = "data-qtip='" + data + "'";
    return data;
  }
}
//renderer
return showTip(record.data.STATE_NOTE_ERROR, metaData, record, rowIndex, colIndex, store);

单元格换行 单元格文字颜色

//首先要够长
value=value.replaceAll('\n','</br>');
value=value.replaceAll('新增','<font color="red">新增</font>');
value=value.replaceAll('更新','<font color="red">更新</font>');
value=value.replaceAll('删除','<font color="red">删除</font>');
return value;
Navigation

Type to search…

↑↓ navigate↵ selectEsc close