devextreme-vue我使用的是23.2版本,其DxDataGrid如何显示行号列,官方一直没有方案。
DataGrid - How to display a row number in data rows in Angular | DevExpress Support
dxDataGrid - provide capability to display a column with row numbers | DevExpress Support
因为涉及到分页、分组、统计,等等,其row.rowType有:“data”、"detail"、"detailAdaptive"、groupFooter"、"header"、"filter"、"totalFooter"、“group”这很多种,我们想要的是计算“data”类型的行的行号。rowInfo的rowIndex,dataIndex,loadIndex都不能真实的反映“资料行号”,用pageIndex*pageSize+rowIndex+1计算都是错误的。
看起来自己在dataSource中为每个row计算一个rowNumber值可能比较靠谱。要考虑几个问题:
(1)计算的时机:
- 点击column排序,
- 拖动column分组,
- filter栏打入文字,
- 搜索框打入文字,
- 增加、删除一行资料
- dataSouce改变
- ...
前面5个,可以监听option-changed事件:
<template>
<DxDataGrid ref="gridBackend" @option-changed="onOptionChanged" />
</template><script setup>
import { ref, nextTick, onMounted, onUnmounted, watch } from 'vue';
import {DxDataGrid, DxColumn, DxPager, DxPaging, DxGroupPanel,DxSearchPanel, DxSearch, DxLoadPanel, DxEditing,DxColumnChooser, DxSelection, DxColumnFixing,DxFilterRow, DxFilterPanel, DxHeaderFilter, DxSorting,DxScrolling, DxSummary, DxTotalItem
} from 'devextreme-vue/data-grid';
import { DxTabPanel, DxItem as DxTabPanelItem } from 'devextreme-vue/tab-panel';
import ArrayStore from 'devextreme/data/array_store';
import DataSource from 'devextreme/data/data_source'
let gridBackend = ref();const onOptionChanged = function (e) {//console.log(e);if (e.fullName.includes('filter') ||e.fullName.includes('sort') ||e.fullName.includes('group') ||e.fullName.includes('search') ||e.fullName == 'editing.changes') {nextTick(function () {recomputeRowNumber(gridBackend.value, dataSourceBackendMonitors.value);});}
}
</script>
第6个是你改变数据集的时候。
(2)如何对数据集排序过滤;
DxDataGrid在排序过滤时,不会改变原始数据集,我想找到它处理后的数据集,然后计算一个rowNumber,但是翻了源码,它没有保存这个完整的排序过滤后的数据集。但找到一些方法来计算,不用自己写计算逻辑。
function recomputeRowNumber(dxGrid, dataSet) {let dc = dxGrid.instance.getController('data');let ds = dxGrid.instance.getDataSource();/*** 不能通过ds.loadOptions();获取参数,获取到的ops是store中的,赋值filter后,它会存起来,* 过滤行的filtervalue清掉后,dc.getCombinedFilter还是会从store返回之前的。*///let ops = ds.loadOptions();//ops.filter = dc.getCombinedFilter();// console.log('参数:',ds.filter(),dc.getCombinedFilter());let ops = {requireTotalCount: false,filter: dc.getCombinedFilter(),group: ds.group(),sort: ds.sort()}//console.log('参数:',ops);//ds.store().load(ops)new ArrayStore(dataSet).load(ops).done(function (items) {//console.log('买', ops, items);let rowNumber = 0;let groupLevels = -1;if (ops.group) groupLevels = ops.group.length;function modifyRecords(items, groupLevel) {items.forEach(function (item) {if (groupLevel < groupLevels) {modifyRecords(item.items, groupLevel + 1);}else {rowNumber++;item.rowNumber = rowNumber;}});}modifyRecords(items, 0);});
}
(3)如何显示
想显示在最左边,不要受分组列影响,需要把分组列放在第2列,设定一个type="groupExpand"的列:
<DxColumn data-field="OID" width="50" :visible="false" :fixed="true" :allow-filtering="false":allow-sorting="false" :allow-grouping="false" :allowEditing="false" :allowAdding="false" /><DxColumn caption="#" data-field="rowNumber" width="50" alignment="center" :fixed="true":allow-filtering="false" :allow-sorting="false" :allow-grouping="false" :allowEditing="false":allowAdding="false" /><DxColumn type="groupExpand" />
(4)优化
- 因为是在nextTick之中,即渲染后再修改,因此rowNumber列会有个闪烁,不知如何避免。
- optionChanges事件,在打入过滤值时可能会触发3次,如何防抖?用一个timer:
let recomputeRowNumberTimer; const onOptionChanged = function (e) {...nextTick(function () {if (recomputeRowNumberTimer) clearTimeout(recomputeRowNumberTimer);recomputeRowNumberTimer=setTimeout(function(){recomputeRowNumber(gridBackend.value, dataSourceBackendMonitors.value);},0);});
效果为: