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