Skip to content

Commit 4c5ee8d

Browse files
committed
Page mode, Perf improvement
1 parent 31ea479 commit 4c5ee8d

File tree

5 files changed

+115
-27
lines changed

5 files changed

+115
-27
lines changed

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,22 @@ Here is an example:
153153
</virtual-scroller>
154154
```
155155

156+
## Page mode
157+
158+
The page mode expand the virtual-scroller and use the page viewport to compute which items are visible. That way, you can use it in a big page with HTML elements before or after (like a header and a footer). Just set the `page-mode` props to `true`:
159+
160+
```html
161+
<header>
162+
<menu></menu>
163+
</header>
164+
165+
<virtual-scroller page-mode></virtual-scroller>
166+
167+
<footer>
168+
Copyright 2017 - Cat
169+
</footer>
170+
```
171+
156172
## Customizing the tags
157173

158174
These are optional props you can use to change the DOM tags used in the virtual scroller:

dist/vue-virtual-scroller.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
.virtual-scroller[data-v-5594e8c4] {
2+
.virtual-scroller[data-v-5594e8c4]:not(.page-mode) {
33
overflow-y: auto;
44
}
55
.item-container[data-v-5594e8c4] {

dist/vue-virtual-scroller.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "vue-virtual-scroller",
33
"description": "Smooth scrolling for any amount of data",
4-
"version": "0.4.3",
4+
"version": "0.5.0",
55
"author": {
66
"name": "Guillaume Chau",
77
"email": "[email protected]"

src/components/VirtualScroller.vue

Lines changed: 96 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
<template>
2-
<component :is="mainTag" class="virtual-scroller" @scroll="updateVisibleItems" v-observe-visibility="handleVisibilityChange">
2+
<component :is="mainTag" class="virtual-scroller" :class="cssClass" @scroll="updateVisibleItems" v-observe-visibility="handleVisibilityChange">
33
<component :is="containerTag" class="item-container" :style="itemContainerStyle">
44
<component :is="contentTag" class="items" :style="itemsStyle">
55
<template v-if="renderers">
6-
<component class="item" v-for="item in visibleItems" :key="item[keyField]" :is="renderers[item[typeField]]" :item="item"></component>
6+
<component class="item" v-for="item in visibleItems" :key="keysEnabled && item[keyField]" :is="renderers[item[typeField]]" :item="item"></component>
77
</template>
88
<template v-else>
99
<slot class="item" v-for="item in visibleItems" :item="item"></slot>
@@ -61,46 +61,97 @@ export default {
6161
type: String,
6262
default: 'div',
6363
},
64+
pageMode: {
65+
type: Boolean,
66+
default: false,
67+
},
6468
},
6569
6670
data: () => ({
6771
visibleItems: [],
6872
itemContainerStyle: null,
6973
itemsStyle: null,
74+
keysEnabled: true,
7075
}),
7176
77+
computed: {
78+
cssClass () {
79+
return {
80+
'page-mode': this.pageMode,
81+
}
82+
},
83+
},
84+
7285
watch: {
7386
items () {
7487
this.updateVisibleItems()
7588
},
89+
pageMode () {
90+
this.applyPageMode()
91+
this.updateVisibleItems()
92+
},
7693
},
7794
7895
methods: {
79-
updateVisibleItems () {
80-
const l = this.items.length
96+
getScroll () {
8197
const el = this.$el
82-
const scroll = {
83-
top: el.scrollTop,
84-
bottom: el.scrollTop + el.clientHeight,
85-
}
86-
this._startIndex = Math.floor(scroll.top / this.itemHeight)
87-
this._endIndex = Math.ceil(scroll.bottom / this.itemHeight)
88-
let startIndex = this._startIndex - 1
89-
if (startIndex < 0) {
90-
startIndex = 0
91-
}
92-
let endIndex = this._endIndex + 2
93-
if (endIndex > l) {
94-
endIndex = l
98+
let scroll
99+
100+
if (this.pageMode) {
101+
const rect = el.getBoundingClientRect()
102+
let top = -rect.top
103+
let height = window.innerHeight
104+
if (top < 0) {
105+
height += top
106+
top = 0
107+
}
108+
if (top + height > rect.height) {
109+
height = rect.height - top
110+
}
111+
scroll = {
112+
top: top,
113+
bottom: top + height,
114+
}
115+
} else {
116+
scroll = {
117+
top: el.scrollTop,
118+
bottom: el.scrollTop + el.clientHeight,
119+
}
95120
}
96-
this.visibleItems = this.items.slice(startIndex, endIndex)
97-
this.itemContainerStyle = {
98-
height: l * this.itemHeight + 'px',
121+
122+
if (scroll.bottom >= 0 && scroll.top <= scroll.bottom) {
123+
return scroll
124+
} else {
125+
return null
99126
}
100-
this.itemsStyle = {
101-
marginTop: startIndex * this.itemHeight + 'px',
127+
},
128+
129+
updateVisibleItems () {
130+
const l = this.items.length
131+
const scroll = this.getScroll()
132+
if (scroll) {
133+
let startIndex = Math.floor(scroll.top / this.itemHeight)
134+
let endIndex = Math.ceil(scroll.bottom / this.itemHeight)
135+
startIndex -= 1
136+
if (startIndex < 0) {
137+
startIndex = 0
138+
}
139+
endIndex += 2
140+
if (endIndex > l) {
141+
endIndex = l
142+
}
143+
this.keysEnabled = !(startIndex > this._endIndex || endIndex < this._startIndex)
144+
this._startIndex = startIndex
145+
this._endIndex = endIndex
146+
this.visibleItems = this.items.slice(startIndex, endIndex)
147+
this.itemContainerStyle = {
148+
height: l * this.itemHeight + 'px',
149+
}
150+
this.itemsStyle = {
151+
marginTop: startIndex * this.itemHeight + 'px',
152+
}
153+
this.$forceUpdate()
102154
}
103-
this.$forceUpdate()
104155
},
105156
106157
scrollToItem (index) {
@@ -114,16 +165,37 @@ export default {
114165
})
115166
}
116167
},
168+
169+
applyPageMode () {
170+
if (this.pageMode) {
171+
this.addWindowScroll()
172+
} else {
173+
this.removeWindowScroll()
174+
}
175+
},
176+
177+
addWindowScroll () {
178+
window.addEventListener('scroll', this.updateVisibleItems, true)
179+
},
180+
181+
removeWindowScroll () {
182+
window.removeEventListener('scroll', this.updateVisibleItems, true)
183+
},
117184
},
118185
119186
mounted () {
120187
this.updateVisibleItems()
188+
this.applyPageMode()
189+
},
190+
191+
beforeDestroy () {
192+
this.removeWindowScroll()
121193
},
122194
}
123195
</script>
124196

125197
<style scoped>
126-
.virtual-scroller {
198+
.virtual-scroller:not(.page-mode) {
127199
overflow-y: auto;
128200
}
129201

0 commit comments

Comments
 (0)