Initiated VirtualScroll Table
parent
2889aeae5b
commit
24b3ac7ae0
|
@ -61,7 +61,7 @@
|
|||
@row-edit-init="onRowEditInit($event)" @row-edit-save="onRowEditSave($event)" @row-edit-cancel="onRowEditCancel($event)"/>
|
||||
</template>
|
||||
<template #frozenbody>
|
||||
<DTTableBody :value="frozenValue" :columns="frozenColumns" :dataKey="dataKey" :selection="selection" :selectionKeys="d_selectionKeys" :selectionMode="selectionMode"
|
||||
<DTTableBody v-if="frozenValue" :value="frozenValue" :columns="frozenColumns" :dataKey="dataKey" :selection="selection" :selectionKeys="d_selectionKeys" :selectionMode="selectionMode"
|
||||
:rowGroupMode="rowGroupMode" :groupRowsBy="groupRowsBy" :expandableRowGroups="expandableRowGroups" :rowClass="rowClass" :editMode="editMode" :compareSelectionBy="compareSelectionBy"
|
||||
:expandedRowIcon="expandedRowIcon" :collapsedRowIcon="collapsedRowIcon" :expandedRows="expandedRows" :expandedRowKeys="d_expandedRowKeys" :expandedRowGroups="expandedRowGroups"
|
||||
:editingRows="editingRows" :editingRowKeys="d_editingRowKeys" :templates="$scopedSlots"
|
||||
|
@ -75,7 +75,8 @@
|
|||
<DTTableFooter :columnGroup="frozenFooterColumnGroup" :columns="frozenColumns" />
|
||||
</template>
|
||||
</DTScrollableView>
|
||||
<DTScrollableView :scrollHeight="scrollHeight" :columns="scrollableColumns" :frozenWidth="frozenWidth">
|
||||
<DTScrollableView :scrollHeight="scrollHeight" :columns="scrollableColumns" :frozenWidth="frozenWidth" :rows="rows"
|
||||
:virtualScroll="virtualScroll" :virtualRowHeight="virtualRowHeight" :totalRecords="totalRecordsLength" @virtual-scroll="onVirtualScroll">
|
||||
<template #header>
|
||||
<DTTableHeader :columnGroup="headerColumnGroup" :columns="scrollableColumns" :rowGroupMode="rowGroupMode"
|
||||
:groupRowsBy="groupRowsBy" :resizableColumns="resizableColumns" :allRowsSelected="allRowsSelected" :empty="empty"
|
||||
|
@ -96,7 +97,7 @@
|
|||
@row-edit-init="onRowEditInit($event)" @row-edit-save="onRowEditSave($event)" @row-edit-cancel="onRowEditCancel($event)"/>
|
||||
</template>
|
||||
<template #frozenbody>
|
||||
<DTTableBody :value="frozenValue" :columns="scrollableColumns" :dataKey="dataKey" :selection="selection" :selectionKeys="d_selectionKeys" :selectionMode="selectionMode"
|
||||
<DTTableBody v-if="frozenValue" :value="frozenValue" :columns="scrollableColumns" :dataKey="dataKey" :selection="selection" :selectionKeys="d_selectionKeys" :selectionMode="selectionMode"
|
||||
:rowGroupMode="rowGroupMode" :groupRowsBy="groupRowsBy" :expandableRowGroups="expandableRowGroups" :rowClass="rowClass" :editMode="editMode" :compareSelectionBy="compareSelectionBy"
|
||||
:expandedRowIcon="expandedRowIcon" :collapsedRowIcon="collapsedRowIcon" :expandedRows="expandedRows" :expandedRowKeys="d_expandedRowKeys" :expandedRowGroups="expandedRowGroups"
|
||||
:editingRows="editingRows" :editingRowKeys="d_editingRowKeys" :templates="$scopedSlots"
|
||||
|
@ -332,6 +333,18 @@ export default {
|
|||
frozenWidth: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
virtualScroll: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
virtualRowHeight: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
virtualScrollDelay: {
|
||||
type: Number,
|
||||
default: 159
|
||||
}
|
||||
},
|
||||
data() {
|
||||
|
@ -365,6 +378,7 @@ export default {
|
|||
columnWidthsState: null,
|
||||
tableWidthState: null,
|
||||
columnWidthsRestored: false,
|
||||
virtualScrollTimer: null,
|
||||
watch: {
|
||||
first(newValue) {
|
||||
this.d_first = newValue;
|
||||
|
@ -1488,7 +1502,19 @@ export default {
|
|||
_editingRows.splice(this.findIndex(event.data, this._editingRows), 1);
|
||||
this.$emit('update:editingRows', _editingRows);
|
||||
this.$emit('row-edit-cancel', event);
|
||||
}
|
||||
},
|
||||
onVirtualScroll(event) {
|
||||
if(this.virtualScrollTimer) {
|
||||
clearTimeout(this.virtualScrollTimer);
|
||||
}
|
||||
|
||||
this.virtualScrollTimer = setTimeout(() => {
|
||||
this.$emit('virtual-scroll', {
|
||||
first: (event.page - 1) * this.rows,
|
||||
rows: this.rows * 2
|
||||
});
|
||||
}, this.virtualScrollDelay);
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
containerClass() {
|
||||
|
@ -1498,7 +1524,8 @@ export default {
|
|||
'p-datatable-auto-layout': this.autoLayout,
|
||||
'p-datatable-resizable': this.resizableColumns,
|
||||
'p-datatable-resizable-fit': this.resizableColumns && this.columnResizeMode === 'fit',
|
||||
'p-datatable-scrollable': this.scrollable
|
||||
'p-datatable-scrollable': this.scrollable,
|
||||
'p-datatable-virtual-scrollable': this.virtualScroll
|
||||
}
|
||||
];
|
||||
},
|
||||
|
|
|
@ -12,12 +12,18 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="p-datatable-scrollable-body" ref="scrollBody" @scroll="onBodyScroll">
|
||||
<table ref="scrollTable">
|
||||
<table ref="scrollTable" :class="bodyTableClass" :style="bodyTableStyle">
|
||||
<colgroup class="p-datatable-scrollable-colgroup">
|
||||
<col v-for="(col,i) of columns" :key="col.columnKey||col.field||i" :style="col.headerStyle" />
|
||||
</colgroup>
|
||||
<slot name="body"></slot>
|
||||
</table>
|
||||
<table ref="loadingTable" :style="{top:'0', display: 'none'}" class="p-datatable-scrollable-body-table p-datatable-loading-virtual-table p-datatable-virtual-table">
|
||||
<colgroup class="p-datatable-scrollable-colgroup">
|
||||
<col v-for="(col,i) of columns" :key="col.columnKey||col.field||i" :style="col.headerStyle" />
|
||||
</colgroup>
|
||||
</table>
|
||||
<div class="p-datatable-virtual-scroller" ref="virtualScroller"></div>
|
||||
</div>
|
||||
<div class="p-datatable-scrollable-footer" ref="scrollFooter">
|
||||
<div class="p-datatable-scrollable-footer-box" ref="scrollFooterBox">
|
||||
|
@ -52,8 +58,25 @@ export default {
|
|||
scrollHeight: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
virtualScroll: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
virtualRowHeight: {
|
||||
type: Number,
|
||||
default: null
|
||||
},
|
||||
rows: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
totalRecords: {
|
||||
type: Number,
|
||||
default: 0
|
||||
}
|
||||
},
|
||||
virtualScrollCallback: null,
|
||||
mounted() {
|
||||
this.setScrollHeight();
|
||||
|
||||
|
@ -61,10 +84,29 @@ export default {
|
|||
this.alignScrollBar();
|
||||
else
|
||||
this.$refs.scrollBody.style.paddingBottom = DomHandler.calculateScrollbarWidth() + 'px';
|
||||
|
||||
if (this.virtualScroll) {
|
||||
this.$refs.virtualScroller.style.height = this.totalRecords * this.virtualRowHeight + 'px';
|
||||
}
|
||||
},
|
||||
updated() {
|
||||
if (!this.frozen) {
|
||||
this.alignScrollBar();
|
||||
}
|
||||
|
||||
if (this.virtualScrollCallback) {
|
||||
this.virtualScrollCallback();
|
||||
this.virtualScrollCallback = null;
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
scrollHeight() {
|
||||
this.setScrollHeight();
|
||||
},
|
||||
totalRecords(newValue) {
|
||||
if (this.virtualScroll) {
|
||||
this.$refs.virtualScroller.style.height = newValue * this.virtualRowHeight + 'px';
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
@ -78,45 +120,43 @@ export default {
|
|||
frozenScrollBody = DomHandler.findSingle(frozenView, '.p-datatable-scrollable-body');
|
||||
}
|
||||
|
||||
if (frozenScrollBody) {
|
||||
frozenScrollBody.scrollTop = this.$refs.scrollBody.scrollTop;
|
||||
}
|
||||
|
||||
this.$refs.scrollHeaderBox.style.marginLeft = -1 * this.$refs.scrollBody.scrollLeft + 'px';
|
||||
if (this.$refs.scrollFooterBox) {
|
||||
this.$refs.scrollFooterBox.style.marginLeft = -1 * this.$refs.scrollBody.scrollLeft + 'px';
|
||||
}
|
||||
|
||||
if (frozenScrollBody) {
|
||||
frozenScrollBody.scrollTop = this.$refs.scrollBody.scrollTop;
|
||||
}
|
||||
/*
|
||||
if (this.props.virtualScroll) {
|
||||
let viewport = DomHandler.getClientHeight(this.scrollBody);
|
||||
let tableHeight = DomHandler.getOuterHeight(this.scrollTable);
|
||||
let pageHeight = this.props.virtualRowHeight * this.props.rows;
|
||||
let virtualTableHeight = DomHandler.getOuterHeight(this.virtualScroller);
|
||||
|
||||
if (this.virtualScroll) {
|
||||
let viewport = DomHandler.getClientHeight(this.$refs.scrollBody);
|
||||
let tableHeight = DomHandler.getOuterHeight(this.$refs.scrollTable);
|
||||
let pageHeight = this.virtualRowHeight * this.rows;
|
||||
let virtualTableHeight = DomHandler.getOuterHeight(this.$refs.virtualScroller);
|
||||
let pageCount = (virtualTableHeight / pageHeight)||1;
|
||||
let scrollBodyTop = this.scrollTable.style.top||'0';
|
||||
let scrollBodyTop = this.$refs.scrollTable.style.top||'0';
|
||||
|
||||
if(this.scrollBody.scrollTop + viewport > parseFloat(scrollBodyTop) + tableHeight || this.scrollBody.scrollTop < parseFloat(scrollBodyTop)) {
|
||||
if (this.loadingTable) {
|
||||
this.loadingTable.style.display = 'table';
|
||||
this.loadingTable.style.top = this.scrollBody.scrollTop + 'px';
|
||||
if(this.$refs.scrollBody.scrollTop + viewport > parseFloat(scrollBodyTop) + tableHeight || this.$refs.scrollBody.scrollTop < parseFloat(scrollBodyTop)) {
|
||||
if (this.$refs.loadingTable) {
|
||||
this.$refs.loadingTable.style.display = 'table';
|
||||
this.$refs.loadingTable.style.top = this.$refs.scrollBody.scrollTop + 'px';
|
||||
}
|
||||
|
||||
let page = Math.floor((this.scrollBody.scrollTop * pageCount) / (this.scrollBody.scrollHeight)) + 1;
|
||||
if(this.props.onVirtualScroll) {
|
||||
this.props.onVirtualScroll({
|
||||
page: page
|
||||
});
|
||||
let page = Math.floor((this.$refs.scrollBody.scrollTop * pageCount) / (this.$refs.scrollBody.scrollHeight)) + 1;
|
||||
this.$emit('virtual-scroll', {
|
||||
page: page
|
||||
});
|
||||
|
||||
this.virtualScrollCallback = () => {
|
||||
if (this.loadingTable) {
|
||||
this.loadingTable.style.display = 'none';
|
||||
}
|
||||
|
||||
this.scrollTable.style.top = ((page - 1) * pageHeight) + 'px';
|
||||
this.virtualScrollCallback = () => {
|
||||
if (this.$refs.loadingTable) {
|
||||
this.$refs.loadingTable.style.display = 'none';
|
||||
}
|
||||
|
||||
this.$refs.scrollTable.style.top = ((page - 1) * pageHeight) + 'px';
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
},
|
||||
setScrollHeight() {
|
||||
if (this.scrollHeight) {
|
||||
|
@ -184,6 +224,12 @@ export default {
|
|||
else {
|
||||
return null;
|
||||
}
|
||||
},
|
||||
bodyTableClass() {
|
||||
return ['p-datatable-scrollable-body-table', {'p-datatable-virtual-table': this.virtualScroll}];
|
||||
},
|
||||
bodyTableStyle() {
|
||||
return this.virtualScroll ? {top: '0'} : null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,6 +58,21 @@ export default class DomHandler {
|
|||
}
|
||||
}
|
||||
|
||||
static getClientHeight(el, margin) {
|
||||
if (el) {
|
||||
let height = el.clientHeight;
|
||||
|
||||
if (margin) {
|
||||
let style = getComputedStyle(el);
|
||||
height += parseFloat(style.marginTop) + parseFloat(style.marginBottom);
|
||||
}
|
||||
|
||||
return height;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static getViewport() {
|
||||
let win = window,
|
||||
d = document,
|
||||
|
|
|
@ -18,6 +18,15 @@
|
|||
<Column field="color" header="Color"></Column>
|
||||
</DataTable>
|
||||
|
||||
<h3>Virtual Scroll</h3>
|
||||
<DataTable :value="lazyCars" :scrollable="true" scrollHeight="200px" :lazy="true" :rows="20"
|
||||
:virtualScroll="true" :virtualRowHeight="30" @virtual-scroll="onVirtualScroll" :totalRecords="lazyTotalRecords">
|
||||
<Column field="vin" header="Vin"></Column>
|
||||
<Column field="year" header="Year"></Column>
|
||||
<Column field="brand" header="Brand"></Column>
|
||||
<Column field="color" header="Color"></Column>
|
||||
</DataTable>
|
||||
|
||||
<h3>Horizontal and Vertical</h3>
|
||||
<DataTable :value="cars" :scrollable="true" scrollHeight="200px" style="width: 600px">
|
||||
<Column field="vin" header="Vin" headerStyle="width: 250px" columnKey="vin_1"></Column>
|
||||
|
@ -82,12 +91,58 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
cars: null,
|
||||
frozenCars: null
|
||||
frozenCars: null,
|
||||
lazyCars: null,
|
||||
lazyTotalRecords: 0
|
||||
}
|
||||
},
|
||||
carService: null,
|
||||
inmemoryData: null,
|
||||
created() {
|
||||
this.carService = new CarService();
|
||||
|
||||
this.inmemoryData = [
|
||||
{"brand": "VW", "year": 2012, "color": "Orange"},
|
||||
{"brand": "Audi", "year": 2011, "color": "Black"},
|
||||
{"brand": "Renault", "year": 2005, "color": "Gray"},
|
||||
{"brand": "BMW", "year": 2003, "color": "Blue"},
|
||||
{"brand": "Mercedes", "year": 1995, "color": "Orange"},
|
||||
{"brand": "Volvo", "year": 2005, "color": "Black"},
|
||||
{"brand": "Honda", "year": 2012, "color": "Yellow"},
|
||||
{"brand": "Jaguar", "year": 2013, "color": "Orange"},
|
||||
{"brand": "Ford", "year": 2000, "color": "Black"},
|
||||
{"brand": "Fiat", "year": 2013, "color": "Red"},
|
||||
{"brand": "VW", "year": 2012, "color": "Orange"},
|
||||
{"brand": "Audi", "year": 2011, "color": "Black"},
|
||||
{"brand": "Renault", "year": 2005, "color": "Gray"},
|
||||
{"brand": "BMW", "year": 2003, "color": "Blue"},
|
||||
{"brand": "Mercedes", "year": 1995, "color": "Orange"},
|
||||
{"brand": "Volvo", "year": 2005, "color": "Black"},
|
||||
{"brand": "Honda", "year": 2012, "color": "Yellow"},
|
||||
{"brand": "Jaguar", "year": 2013, "color": "Orange"},
|
||||
{"brand": "Ford", "year": 2000, "color": "Black"},
|
||||
{"brand": "Fiat", "year": 2013, "color": "Red"},
|
||||
{"brand": "VW", "year": 2012, "color": "Orange"},
|
||||
{"brand": "Audi", "year": 2011, "color": "Black"},
|
||||
{"brand": "Renault", "year": 2005, "color": "Gray"},
|
||||
{"brand": "BMW", "year": 2003, "color": "Blue"},
|
||||
{"brand": "Mercedes", "year": 1995, "color": "Orange"},
|
||||
{"brand": "Volvo", "year": 2005, "color": "Black"},
|
||||
{"brand": "Honda", "year": 2012, "color": "Yellow"},
|
||||
{"brand": "Jaguar", "year": 2013, "color": "Orange"},
|
||||
{"brand": "Ford", "year": 2000, "color": "Black"},
|
||||
{"brand": "Fiat", "year": 2013, "color": "Red"},
|
||||
{"brand": "VW", "year": 2012, "color": "Orange"},
|
||||
{"brand": "Audi", "year": 2011, "color": "Black"},
|
||||
{"brand": "Renault", "year": 2005, "color": "Gray"},
|
||||
{"brand": "BMW", "year": 2003, "color": "Blue"},
|
||||
{"brand": "Mercedes", "year": 1995, "color": "Orange"},
|
||||
{"brand": "Volvo", "year": 2005, "color": "Black"},
|
||||
{"brand": "Honda", "year": 2012, "color": "Yellow"},
|
||||
{"brand": "Jaguar", "year": 2013, "color": "Orange"},
|
||||
{"brand": "Ford", "year": 2000, "color": "Black"},
|
||||
{"brand": "Fiat", "year": 2013, "color": "Red"}
|
||||
];
|
||||
},
|
||||
mounted() {
|
||||
this.carService.getCarsLarge().then(data => this.cars = data);
|
||||
|
@ -96,6 +151,34 @@ export default {
|
|||
{brand: "BMW", year: 2013, color: "Grey", vin: "fh2uf23"},
|
||||
{brand: "Chevrolet", year: 2011, color: "Black", vin: "4525g23"}
|
||||
];
|
||||
|
||||
setTimeout(() => {
|
||||
this.lazyCars = this.loadChunk(0, 40);
|
||||
this.lazyTotalRecords = 250000;
|
||||
}, 250);
|
||||
},
|
||||
methods: {
|
||||
loadChunk(index, length) {
|
||||
let chunk = [];
|
||||
for (let i = 0; i < length; i++) {
|
||||
chunk[i] = {...this.inmemoryData[i], ...{vin: (index + i)}};
|
||||
}
|
||||
|
||||
return chunk;
|
||||
},
|
||||
onVirtualScroll(event) {
|
||||
/*
|
||||
For demo purposes keep loading the same dataset,
|
||||
in a real production application, this data should come from server by building the query with LazyLoadEvent options
|
||||
*/
|
||||
setTimeout(() => {
|
||||
//last chunk
|
||||
if (event.first === 249980)
|
||||
this.lazyCars = this.loadChunk(event.first, 20)
|
||||
else
|
||||
this.lazyCars = this.loadChunk(event.first, event.rows)
|
||||
}, 250);
|
||||
}
|
||||
},
|
||||
components: {
|
||||
'DataTableSubMenu': DataTableSubMenu
|
||||
|
|
Loading…
Reference in New Issue