Skip to content

Commit f19af6c

Browse files
authored
feat: update event provide range of the visible items (#115)
1 parent b613318 commit f19af6c

File tree

4 files changed

+77
-21
lines changed

4 files changed

+77
-21
lines changed

Diff for: README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ When the user scrolls inside RecycleScroller, the views are mostly just moved ar
200200
- `resize`: emitted when the size of the scroller changes.
201201
- `visible`: emitted when the scroller considers itself to be visible in the page.
202202
- `hidden`: emitted when the scroller is hidden in the page.
203-
- `update (startIndex, endIndex)`: emitted each time the views are updated, only if `emitUpdate` prop is `true`
203+
- `update (startIndex, endIndex, visibleStartIndex, visibleEndIndex)`: emitted each time the views are updated, only if `emitUpdate` prop is `true`
204204

205205
### Default scoped slot props
206206

Diff for: docs-src/src/components/DynamicScrollerDemo.vue

+24
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@
55
v-model="search"
66
placeholder="Filter..."
77
>
8+
<span>({{ updateParts.viewStartIdx }} - [{{ updateParts.visibleStartIdx }} - {{ updateParts.visibleEndIdx }}] - {{ updateParts.viewEndIdx }})</span>
89
</div>
910

1011
<DynamicScroller
1112
:items="filteredItems"
1213
:min-item-size="54"
14+
:emit-update="true"
1315
class="scroller"
16+
@update="onUpdate"
1417
>
1518
<template #before>
1619
<div class="notice">
@@ -72,6 +75,7 @@ export default {
7275
return {
7376
items,
7477
search: '',
78+
updateParts: { viewStartIdx: 0, viewEndIdx: 0, visibleStartIdx: 0, visibleEndIdx: 0 },
7579
}
7680
},
7781
@@ -88,6 +92,13 @@ export default {
8892
changeMessage (message) {
8993
Object.assign(message, generateMessage())
9094
},
95+
96+
onUpdate (viewStartIndex, viewEndIndex, visibleStartIndex, visibleEndIndex) {
97+
this.updateParts.viewStartIdx = viewStartIndex
98+
this.updateParts.viewEndIdx = viewEndIndex
99+
this.updateParts.visibleStartIdx = visibleStartIndex
100+
this.updateParts.visibleEndIdx = visibleEndIndex
101+
},
91102
},
92103
}
93104
</script>
@@ -102,6 +113,19 @@ export default {
102113
overflow: hidden;
103114
}
104115
116+
.scroller {
117+
border: solid 1px #42b983;
118+
}
119+
120+
.toolbar {
121+
flex: auto 0 0;
122+
text-align: center;
123+
}
124+
125+
.toolbar > *:not(:last-child) {
126+
margin-right: 24px;
127+
}
128+
105129
.notice {
106130
padding: 24px;
107131
font-size: 20px;

Diff for: docs-src/src/components/RecycleScrollerDemo.vue

+24-4
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@
4646
<button @mousedown="renderScroller = !renderScroller">Toggle render</button>
4747
<button @mousedown="showScroller = !showScroller">Toggle visibility</button>
4848
</span>
49+
<label>
50+
<input
51+
v-model="showMessageBeforeItems"
52+
type="checkbox"
53+
> show message before items
54+
</label>
55+
<span>({{ updateParts.viewStartIdx }} - [{{ updateParts.visibleStartIdx }} - {{ updateParts.visibleEndIdx }}] - {{ updateParts.viewEndIdx }})</span>
4956
</div>
5057

5158
<div
@@ -64,6 +71,8 @@
6471
:page-mode="pageMode"
6572
key-field="id"
6673
size-field="height"
74+
:emit-update="true"
75+
@update="onUpdate"
6776
@visible="onVisible"
6877
@hidden="onHidden"
6978
>
@@ -113,6 +122,8 @@ export default {
113122
enableLetters: true,
114123
pageMode: false,
115124
pageModeFullPage: true,
125+
updateParts: { viewStartIdx: 0, viewEndIdx: 0, visibleStartIdx: 0, visibleEndIdx: 0 },
126+
showMessageBeforeItems: true,
116127
}),
117128
118129
computed: {
@@ -138,7 +149,7 @@ export default {
138149
return this.items.map(
139150
item => Object.assign({}, {
140151
random: Math.random(),
141-
}, item)
152+
}, item),
142153
)
143154
},
144155
},
@@ -160,7 +171,7 @@ export default {
160171
methods: {
161172
generateItems () {
162173
console.log('Generating ' + this.count + ' items...')
163-
let time = Date.now()
174+
const time = Date.now()
164175
const items = getData(this.count, this.enableLetters)
165176
console.log('Generated ' + items.length + ' in ' + (Date.now() - time) + 'ms')
166177
this._dirty = true
@@ -171,8 +182,11 @@ export default {
171182
addItem(this.items)
172183
},
173184
174-
onUpdate (startIndex, endIndex) {
175-
this.updateCount++
185+
onUpdate (viewStartIndex, viewEndIndex, visibleStartIndex, visibleEndIndex) {
186+
this.updateParts.viewStartIdx = viewStartIndex
187+
this.updateParts.viewEndIdx = viewEndIndex
188+
this.updateParts.visibleStartIdx = visibleStartIndex
189+
this.updateParts.visibleEndIdx = visibleEndIndex
176190
},
177191
178192
onVisible () {
@@ -227,6 +241,12 @@ export default {
227241
height: 100%;
228242
}
229243
244+
.notice {
245+
padding: 24px;
246+
font-size: 20px;
247+
color: #999;
248+
}
249+
230250
.letter {
231251
text-transform: uppercase;
232252
color: grey;

Diff for: src/components/RecycleScroller.vue

+28-16
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111
>
1212
<div
1313
v-if="$slots.before"
14-
class="vue-recycle-scroller__slot"
1514
ref="before"
15+
class="vue-recycle-scroller__slot"
1616
>
1717
<slot
1818
name="before"
@@ -43,8 +43,8 @@
4343

4444
<div
4545
v-if="$slots.after"
46-
class="vue-recycle-scroller__slot"
4746
ref="after"
47+
class="vue-recycle-scroller__slot"
4848
>
4949
<slot
5050
name="after"
@@ -208,12 +208,12 @@ export default {
208208
})
209209
},
210210
211-
activated() {
212-
const lastPosition = this.$_lastUpdateScrollPosition;
211+
activated () {
212+
const lastPosition = this.$_lastUpdateScrollPosition
213213
if (typeof lastPosition === 'number') {
214214
this.$nextTick(() => {
215-
this.scrollToPosition(lastPosition);
216-
});
215+
this.scrollToPosition(lastPosition)
216+
})
217217
}
218218
},
219219
@@ -306,12 +306,13 @@ export default {
306306
const pool = this.pool
307307
let startIndex, endIndex
308308
let totalSize
309+
let visibleStartIndex, visibleEndIndex
309310
310311
if (!count) {
311-
startIndex = endIndex = totalSize = 0
312+
startIndex = endIndex = visibleStartIndex = visibleEndIndex = totalSize = 0
312313
} else if (this.$_prerender) {
313-
startIndex = 0
314-
endIndex = this.prerender
314+
startIndex = visibleStartIndex = 0
315+
endIndex = visibleEndIndex = this.prerender
315316
totalSize = null
316317
} else {
317318
const scroll = this.getScroll()
@@ -333,15 +334,16 @@ export default {
333334
scroll.end += buffer
334335
335336
// account for leading slot
336-
if (this.$refs.before){
337-
const lead = this.$refs.before.scrollHeight;
338-
scroll.start -= lead;
337+
let beforeSize = 0
338+
if (this.$refs.before) {
339+
beforeSize = this.$refs.before.scrollHeight
340+
scroll.start -= beforeSize
339341
}
340342
341343
// account for trailing slot
342-
if (this.$refs.after){
343-
const trail = this.$refs.after.scrollHeight;
344-
scroll.end += trail;
344+
if (this.$refs.after) {
345+
const afterSize = this.$refs.after.scrollHeight
346+
scroll.end += afterSize
345347
}
346348
347349
// Variable size mode
@@ -378,14 +380,24 @@ export default {
378380
// Bounds
379381
endIndex > count && (endIndex = count)
380382
}
383+
384+
// search visible startIndex
385+
for (visibleStartIndex = startIndex; visibleStartIndex < count && (beforeSize + sizes[visibleStartIndex].accumulator) < scroll.start; visibleStartIndex++);
386+
387+
// search visible endIndex
388+
for (visibleEndIndex = visibleStartIndex; visibleEndIndex < count && (beforeSize + sizes[visibleEndIndex].accumulator) < scroll.end; visibleEndIndex++);
381389
} else {
382390
// Fixed size mode
383391
startIndex = ~~(scroll.start / itemSize)
384392
endIndex = Math.ceil(scroll.end / itemSize)
393+
visibleStartIndex = Math.max(0, Math.floor((scroll.start - beforeSize) / itemSize))
394+
visibleEndIndex = Math.floor((scroll.end - beforeSize) / itemSize)
385395
386396
// Bounds
387397
startIndex < 0 && (startIndex = 0)
388398
endIndex > count && (endIndex = count)
399+
visibleStartIndex < 0 && (visibleStartIndex = 0)
400+
visibleEndIndex > count && (visibleEndIndex = count)
389401
390402
totalSize = count * itemSize
391403
}
@@ -506,7 +518,7 @@ export default {
506518
this.$_startIndex = startIndex
507519
this.$_endIndex = endIndex
508520
509-
if (this.emitUpdate) this.$emit('update', startIndex, endIndex)
521+
if (this.emitUpdate) this.$emit('update', startIndex, endIndex, visibleStartIndex, visibleEndIndex)
510522
511523
// After the user has finished scrolling
512524
// Sort views so text selection is correct

0 commit comments

Comments
 (0)