Akryum / vue-virtual-scroller

⚡️ Blazing fast scrolling for any amount of data
https://vue-virtual-scroller-demo.netlify.app
9.36k stars 896 forks source link

Can't stable getting a bounding rect of a DynamicScrollerItem in DynamicScroller #765

Open vvy6791 opened 1 year ago

vvy6791 commented 1 year ago

Describe the bug

Using DynamicScrollerItems in DynamicScroller with vertical scrolling. I try to get a bounding rect of an item to detect if item visible to user in a scrollable area. And I get a non actual negative values of top or bottom of this rect with a probability of 20-30%.

Reproduction

<template>
<DynamicScroller ref="itemsScroller" :items="items" :min-item-size="10" class="scroller select-none">
    <template v-slot="{ item, index, active }">
        <DynamicScrollerItem :item="item" :data-index="index" :active="active" :size-dependencies="[ item.textPlain ]">
             <div class="p-1" @click="getItemBounds(index)">{{ item.textPlain }}</div> <!-- text can be of very different length, so div - is of very different height -->
        </DynamicScrollerItem>
    </template>
    <template #after>
        <div style="height:10rem"></div>
    </template>
</DynamicScroller>
</template>

<script>
export default {
    props: [
        'items',
    ],
    methods: {
        getItemBounds(itemIndex) {
            const scrollerElement = this.$refs.itemsScroller.$el;
            const scrollerElementRect = scrollerElement.getBoundingClientRect(); // it's always ok
            console.debug('scrollerElement top, bottom, scrollTop', scrollerElementRect.top, scrollerElementRect.bottom, scrollerElement.scrollTop);

            // By the way, I don't know how get item HTML-element in other way. Maybe there is another way?
            const itemElement = scrollerElement.querySelector('[data-index="' + itemIndex + '"]');
            if (itemElement) {
                const itemElementRect = itemElement.getBoundingClientRect(); // it has wrong negative values sometimes
                console.debug('itemElement top, bottom', itemElementRect.top, itemElementRect.bottom);
            } else {
                console.debug('itemElement not found'); // if scroll to far from item
            }
        },
    },
}
</script>

<style scoped>
.scroller {
    height: 100%;
    width: 100%;
    overflow-y: scroll !important;
}
.select-none {
    user-select: none;
}
.p-1 {
    padding: 0.25rem;
}
</style>

Scroll to item (or far of item) of any index and call this.getItemBounds(itemIndex) for it. If item is out of rendered buffer, it's ok, itemElement is null (not found).

If item is in rendered buffer. Good console out:

scrollerElement top, bottom, scrollTop 72 403 652
itemElement top, bottom 222 254

Buggy console out:

scrollerElement top, bottom, scrollTop 72 403 2802
itemElement top, bottom -12729 -12697

The difference (bottom-top=height) is right in both cases. But top and bottom sometimes (and quite often) is a wrong negative values. The items can be visible in scroll area in both cases, and can be not visible (out of scroll area) in both cases. And it does not matter if item is completely visible in the scroll area or partial.

System Info

In Chrome under Win 10
vue-virtual-scroller v.2.0.0-beta.3

Used Package Manager

yarn

Validations