I’m facing an issue with v-for rendering in Vue 2.
Here is a simplified snippet of what I’m working on, a light virtual scroll table. (Codepen) :
<template>
<div @wheel.prevent="onWheel">
<table>
<tr v-for="item of visibleItems"
v-bind:key="item.id">
<td>{{ item.id }}</td>
<td><input :value="item.label"/></td>
</tr>
</table>
</div>
</template>
<script>
export default {
data: {
start: 0,
count: 10,
items: [...Array(100).keys()]
.map((i) => i + 1)
.map((i) => ({
id: i,
label: `Item ${i}`,
})),
visibleItems: [],
},
methods: {
onWheel(event) {
if (event.deltaY < 0) {
this.onScrollUp()
} else if (event.deltaY > 0) {
this.onScrollDown()
}
},
onScrollUp() {
console.log('up')
const index = this.start - 1
if (index < 0) return
this.start = index
// remove last item
this.visibleItems.pop()
// add first item
this.visibleItems.unshift(this.items[this.start])
},
onScrollDown() {
console.log('down')
const index = this.start + 1
if (index >= (this.items.length - this.count)) return
this.start = index
// remove first item
this.visibleItems.shift()
// add last item
this.visibleItems.push(this.items[this.start + this.count])
},
},
mounted() {
this.visibleItems = this.items.slice(0, this.count)
}
};
</script>
When I scroll up on the table, only the items not already shown are rendered, but when I scroll down, all items are rendered.
The thing is, I have inputs in the second column, when one is focused and I scroll up, the focus remains, but when I scroll down, the input loose it’s focus because the row is rendered.
How could I tell Vue to render only the new rows when I scroll down ?