vue-virtual-scroll-list icon indicating copy to clipboard operation
vue-virtual-scroll-list copied to clipboard

Empty space after source list array was changed

Open xrei opened this issue 5 years ago • 8 comments
trafficstars

Sometimes, not always while source array is changing (add new item, delete existing item) the virtual-scroll-list isn't updating as result i see the blank space on div role=group image

but after scrolling couple times it looks as it should

i have source list stored in vuex and updating it by mutations with Vue.set so it should be reactive

btw i made small demo but there it works as it should work, so i dunno where problem is. but sometimes either in demo this problem occurs. to reproduce it maybe height of messages should be completely different sizes. https://codesandbox.io/s/zen-kilby-8gnsq?file=/src/App.vue

xrei avatar Sep 22 '20 00:09 xrei

but after scrolling couple times it looks as it should

This is a very strange and difficult problem to find out, can you try this.$forceUpdate() to see if problem occurs.

tangbc avatar Sep 22 '20 12:09 tangbc

I can confirm this behavior.. It happends everytime when I use array push adding with scrollToBottom() method - with regular scenario - every second or third array push wont show. It doesn't happend when I have to scroll after adding manually (without using scrollToBottom or setting scrollTop). I think the frequency of blank space occurence (there is no listitem DOM element) depends on virtual list height. Scrolling helps because of listitem DOM re-loading. I'am using updatePageModeFront() after every array push - this.$forceUpdate() didn't help.

UPDATE - workaround - lets say that this.messages = source, chat example:

this.messages.push(payload) // add new item to array
this.$refs.chat.updatePageModeFront()  // call for visual update
this.messages.push({ 
    id: this.messages.length + 1,
    message: '',
    nickName: ''
}) // add another placeholder item, that prevent make blank space (IDK why.. but it works) - it wont appear because of v-if="nickName !== ' ' " in my component
setTimeout(() => {
    this.messages.splice(-1, 1) // timeouted remove of last item 
})
this.$refs.chat.scrollToBottom() // perform bottom scroll

It is not perfect, because this is not as smooth as native (you have to add empty item to array and then immediately remove it), but it works

radimhornicek avatar Nov 03 '20 17:11 radimhornicek

I can confirm I have the same issue with a chat I made. My scenario is the same as @radimhornicek , though I'll probably use that workaround as a last resort.

lapprand avatar Dec 14 '20 13:12 lapprand

This problem can be consistently reproduced in this infinite-loading demo https://tangbc.github.io/vue-virtual-scroll-list/#/infinite-loading by scrolling down and once it starts to load, scrolling a little bit back up again. At this time, the empty space occurs and will stay as is until you scroll down again (scrolling up won't update it).

empty-space

ndresx avatar Feb 25 '21 11:02 ndresx

Any updates?

seregqaaa avatar Aug 03 '21 10:08 seregqaaa

in my case it was solution

const list = this.$refs.vList as InstanceType<typeof VirtualList>;
if (!list) return;
list.virtual.checkRange(0, list.keeps - 1);

Wendor avatar Aug 23 '21 16:08 Wendor

I sometimes see a similar issue when I add a new item to the end of my list. I think it is due to handleDataSourcesChange which decides to not render the final few items due to isFront being true.

I don't know why it is checking isFront or isBehind because the new item was not added as a result of scrolling. It is just a new chat message that was received and added to the list of messages. The fact that it checks the scroll direction means I get different behaviour based on which direction I most recently scrolled in, which doesn't sound right.

For example, if the component is currently rendering items 20 to 79, then I add item 80 to the list, the handleDataSourcesChange function will decide to render items 18 to 77 even though I am not doing any scrolling:

handleDataSourcesChange () {
  let start = this.range.start

  if (this.isFront()) {
    start = start - LEADING_BUFFER
  } else if (this.isBehind()) {
    start = start + LEADING_BUFFER
  }

  start = Math.max(start, 0)

  this.updateRange(this.range.start, this.getEndByStart(start))
}

andrewpskelton avatar Oct 14 '21 11:10 andrewpskelton