Fixed #2114 - Dropdown virtual scroll and lazy load dropdown with selected item

pull/2159/head
mertsincan 2022-02-14 12:18:16 +00:00
parent 7573966576
commit 65b617f6ae
2 changed files with 36 additions and 22 deletions

View File

@ -16,7 +16,7 @@
</slot> </slot>
</div> </div>
<Teleport :to="appendTarget" :disabled="appendDisabled"> <Teleport :to="appendTarget" :disabled="appendDisabled">
<transition name="p-connected-overlay" @enter="onOverlayEnter" @leave="onOverlayLeave" @after-leave="onOverlayAfterLeave"> <transition name="p-connected-overlay" @enter="onOverlayEnter" @after-enter="onOverlayAfterEnter" @leave="onOverlayLeave" @after-leave="onOverlayAfterLeave">
<div :ref="overlayRef" :class="panelStyleClass" v-if="overlayVisible" @click="onOverlayClick"> <div :ref="overlayRef" :class="panelStyleClass" v-if="overlayVisible" @click="onOverlayClick">
<slot name="header" :value="modelValue" :options="visibleOptions"></slot> <slot name="header" :value="modelValue" :options="visibleOptions"></slot>
<div class="p-dropdown-header" v-if="filter"> <div class="p-dropdown-header" v-if="filter">
@ -437,21 +437,25 @@ export default {
onOverlayEnter(el) { onOverlayEnter(el) {
ZIndexUtils.set('overlay', el, this.$primevue.config.zIndex.overlay); ZIndexUtils.set('overlay', el, this.$primevue.config.zIndex.overlay);
this.alignOverlay(); this.alignOverlay();
this.bindOutsideClickListener();
this.bindScrollListener();
this.bindResizeListener();
this.scrollValueInView(); this.scrollValueInView();
if (this.filter) {
this.$refs.filterInput.focus();
}
if (!this.virtualScrollerDisabled) { if (!this.virtualScrollerDisabled) {
const selectedIndex = this.getSelectedOptionIndex(); const selectedIndex = this.getSelectedOptionIndex();
if (selectedIndex !== -1) { if (selectedIndex !== -1) {
this.virtualScroller.scrollToIndex(selectedIndex); setTimeout(() => {
this.virtualScroller && this.virtualScroller.scrollToIndex(selectedIndex)
}, 0);
} }
} }
},
onOverlayAfterEnter() {
if (this.filter) {
this.$refs.filterInput.focus();
}
this.bindOutsideClickListener();
this.bindScrollListener();
this.bindResizeListener();
this.$emit('show'); this.$emit('show');
}, },

View File

@ -148,23 +148,26 @@ export default {
scrollToIndex(index, behavior = 'auto') { scrollToIndex(index, behavior = 'auto') {
const both = this.isBoth(); const both = this.isBoth();
const horizontal = this.isHorizontal(); const horizontal = this.isHorizontal();
const first = this.first;
const { numToleratedItems } = this.calculateNumItems();
const itemSize = this.itemSize;
const contentPos = this.getContentPosition(); const contentPos = this.getContentPosition();
const calculateFirst = (_index = 0, _numT) => (_index <= _numT ? 0 : _index); const calculateFirst = (_index = 0, _numT) => (_index <= _numT ? 0 : _index);
const calculateCoord = (_first, _size, _cpos) => (_first * _size) + _cpos; const calculateCoord = (_first, _size, _cpos) => (_first * _size) + _cpos;
const scrollTo = (left = 0, top = 0) => this.scrollTo({ left, top, behavior }); const scrollTo = (left = 0, top = 0) => this.scrollTo({ left, top, behavior });
if (both) { if (both) {
const newFirst = { rows: calculateFirst(index[0], this.d_numToleratedItems[0]), cols: calculateFirst(index[1], this.d_numToleratedItems[1]) }; const newFirst = { rows: calculateFirst(index[0], numToleratedItems[0]), cols: calculateFirst(index[1], numToleratedItems[1]) };
if (newFirst.rows !== this.first.rows || newFirst.cols !== this.first.cols) { if (newFirst.rows !== first.rows || newFirst.cols !== first.cols) {
scrollTo(calculateCoord(newFirst.cols, this.itemSize[1], contentPos.left), calculateCoord(newFirst.rows, this.itemSize[0], contentPos.top)) scrollTo(calculateCoord(newFirst.cols, itemSize[1], contentPos.left), calculateCoord(newFirst.rows, itemSize[0], contentPos.top))
this.first = newFirst; this.first = newFirst;
} }
} }
else { else {
const newFirst = calculateFirst(index, this.d_numToleratedItems); const newFirst = calculateFirst(index, numToleratedItems);
if (newFirst !== this.first) { if (newFirst !== first) {
horizontal ? scrollTo(calculateCoord(newFirst, this.itemSize, contentPos.left), 0) : scrollTo(0, calculateCoord(newFirst, this.itemSize, contentPos.top)); horizontal ? scrollTo(calculateCoord(newFirst, itemSize, contentPos.left), 0) : scrollTo(0, calculateCoord(newFirst, itemSize, contentPos.top));
this.first = newFirst; this.first = newFirst;
} }
} }
@ -247,26 +250,33 @@ export default {
} }
}; };
}, },
calculateOptions() { calculateNumItems() {
const both = this.isBoth(); const both = this.isBoth();
const horizontal = this.isHorizontal(); const horizontal = this.isHorizontal();
const itemSize = this.itemSize;
const contentPos = this.getContentPosition(); const contentPos = this.getContentPosition();
const contentWidth = this.element ? this.element.offsetWidth - contentPos.left : 0; const contentWidth = this.element ? this.element.offsetWidth - contentPos.left : 0;
const contentHeight = this.element ? this.element.offsetHeight - contentPos.top : 0; const contentHeight = this.element ? this.element.offsetHeight - contentPos.top : 0;
const calculateNumItemsInViewport = (_contentSize, _itemSize) => Math.ceil(_contentSize / (_itemSize || _contentSize)); const calculateNumItemsInViewport = (_contentSize, _itemSize) => Math.ceil(_contentSize / (_itemSize || _contentSize));
const calculateNumToleratedItems = (_numItems) => Math.ceil(_numItems / 2); const calculateNumToleratedItems = (_numItems) => Math.ceil(_numItems / 2);
const numItemsInViewport = both ? const numItemsInViewport = both ?
{ rows: calculateNumItemsInViewport(contentHeight, this.itemSize[0]), cols: calculateNumItemsInViewport(contentWidth, this.itemSize[1]) } : { rows: calculateNumItemsInViewport(contentHeight, itemSize[0]), cols: calculateNumItemsInViewport(contentWidth, itemSize[1]) } :
calculateNumItemsInViewport((horizontal ? contentWidth : contentHeight), this.itemSize); calculateNumItemsInViewport((horizontal ? contentWidth : contentHeight), itemSize);
let numToleratedItems = this.d_numToleratedItems || (both ? const numToleratedItems = this.d_numToleratedItems || (both ?
[calculateNumToleratedItems(numItemsInViewport.rows), calculateNumToleratedItems(numItemsInViewport.cols)] : [calculateNumToleratedItems(numItemsInViewport.rows), calculateNumToleratedItems(numItemsInViewport.cols)] :
calculateNumToleratedItems(numItemsInViewport)); calculateNumToleratedItems(numItemsInViewport));
return { numItemsInViewport, numToleratedItems };
},
calculateOptions() {
const both = this.isBoth();
const first = this.first;
const { numItemsInViewport, numToleratedItems } = this.calculateNumItems();
const calculateLast = (_first, _num, _numT, _isCols) => this.getLast(_first + _num + ((_first < _numT ? 2 : 3) * _numT), _isCols); const calculateLast = (_first, _num, _numT, _isCols) => this.getLast(_first + _num + ((_first < _numT ? 2 : 3) * _numT), _isCols);
const last = both ? const last = both ?
{ rows: calculateLast(this.first.rows, numItemsInViewport.rows, numToleratedItems[0]), cols: calculateLast(this.first.cols, numItemsInViewport.cols, numToleratedItems[1], true) } : { rows: calculateLast(first.rows, numItemsInViewport.rows, numToleratedItems[0]), cols: calculateLast(first.cols, numItemsInViewport.cols, numToleratedItems[1], true) } :
calculateLast(this.first, numItemsInViewport, numToleratedItems); calculateLast(first, numItemsInViewport, numToleratedItems);
this.last = last; this.last = last;
this.numItemsInViewport = numItemsInViewport; this.numItemsInViewport = numItemsInViewport;
@ -280,7 +290,7 @@ export default {
} }
if (this.lazy) { if (this.lazy) {
this.$emit('lazy-load', { first: this.first, last }); this.$emit('lazy-load', { first, last });
} }
}, },
getLast(last = 0, isCols) { getLast(last = 0, isCols) {