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); });
效果为: