Skip to content

Commit dc21471

Browse files
author
Guillaume Chau
committed
refactor: remove Scroller mixin
1 parent ce97b64 commit dc21471

File tree

2 files changed

+178
-187
lines changed

2 files changed

+178
-187
lines changed

src/components/RecycleScroller.vue

Lines changed: 178 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,77 @@
4343
</template>
4444

4545
<script>
46-
import Scroller from '../mixins/Scroller'
46+
import { ResizeObserver } from 'vue-resize'
47+
import { ObserveVisibility } from 'vue-observe-visibility'
48+
import ScrollParent from 'scrollparent'
4749
import config from '../config'
50+
import { supportsPassive } from '../utils'
4851
4952
let uid = 0
5053
5154
export default {
5255
name: 'RecycleScroller',
5356
54-
mixins: [
55-
Scroller,
56-
],
57+
components: {
58+
ResizeObserver,
59+
},
60+
61+
directives: {
62+
ObserveVisibility,
63+
},
64+
65+
props: {
66+
67+
items: {
68+
type: Array,
69+
required: true,
70+
},
71+
72+
itemHeight: {
73+
type: Number,
74+
default: null,
75+
},
76+
77+
minItemHeight: {
78+
type: [Number, String],
79+
default: null,
80+
},
81+
82+
heightField: {
83+
type: String,
84+
default: 'height',
85+
},
86+
87+
typeField: {
88+
type: String,
89+
default: 'type',
90+
},
91+
92+
keyField: {
93+
type: String,
94+
default: 'id',
95+
},
96+
97+
buffer: {
98+
type: Number,
99+
default: 200,
100+
},
101+
102+
pageMode: {
103+
type: Boolean,
104+
default: false,
105+
},
106+
107+
prerender: {
108+
type: Number,
109+
default: 0,
110+
},
111+
112+
emitUpdate: {
113+
type: Boolean,
114+
default: false,
115+
},
116+
},
57117
58118
data () {
59119
return {
@@ -64,6 +124,28 @@ export default {
64124
}
65125
},
66126
127+
computed: {
128+
heights () {
129+
if (this.itemHeight === null) {
130+
const heights = {
131+
'-1': { accumulator: 0 },
132+
}
133+
const items = this.items
134+
const field = this.heightField
135+
const minItemHeight = this.minItemHeight
136+
let accumulator = 0
137+
let current
138+
for (let i = 0, l = items.length; i < l; i++) {
139+
current = items[i][field] || minItemHeight
140+
accumulator += current
141+
heights[i] = { accumulator, height: current }
142+
}
143+
return heights
144+
}
145+
return []
146+
},
147+
},
148+
67149
watch: {
68150
items () {
69151
this.updateVisibleItems(true)
@@ -102,6 +184,10 @@ export default {
102184
})
103185
},
104186
187+
beforeDestroy () {
188+
this.removeListeners()
189+
},
190+
105191
methods: {
106192
addView (pool, index, item, key, type) {
107193
const view = {
@@ -366,6 +452,94 @@ export default {
366452
continuous,
367453
}
368454
},
455+
456+
getListenerTarget () {
457+
let target = ScrollParent(this.$el)
458+
// Fix global scroll target for Chrome and Safari
459+
if (target === window.document.documentElement || target === window.document.body) {
460+
target = window
461+
}
462+
return target
463+
},
464+
465+
getScroll () {
466+
const el = this.$el
467+
// const wrapper = this.$refs.wrapper
468+
let scrollState
469+
470+
if (this.pageMode) {
471+
const size = el.getBoundingClientRect()
472+
let top = -size.top
473+
let height = window.innerHeight
474+
if (top < 0) {
475+
height += top
476+
top = 0
477+
}
478+
if (top + height > size.height) {
479+
height = size.height - top
480+
}
481+
scrollState = {
482+
top,
483+
bottom: top + height,
484+
}
485+
} else {
486+
scrollState = {
487+
top: el.scrollTop,
488+
bottom: el.scrollTop + el.clientHeight,
489+
}
490+
}
491+
492+
return scrollState
493+
},
494+
495+
applyPageMode () {
496+
if (this.pageMode) {
497+
this.addListeners()
498+
} else {
499+
this.removeListeners()
500+
}
501+
},
502+
503+
addListeners () {
504+
this.listenerTarget = this.getListenerTarget()
505+
this.listenerTarget.addEventListener('scroll', this.handleScroll, supportsPassive ? {
506+
passive: true,
507+
} : false)
508+
this.listenerTarget.addEventListener('resize', this.handleResize)
509+
},
510+
511+
removeListeners () {
512+
if (!this.listenerTarget) {
513+
return
514+
}
515+
516+
this.listenerTarget.removeEventListener('scroll', this.handleScroll)
517+
this.listenerTarget.removeEventListener('resize', this.handleResize)
518+
519+
this.listenerTarget = null
520+
},
521+
522+
scrollToItem (index) {
523+
let scrollTop
524+
if (this.itemHeight === null) {
525+
scrollTop = index > 0 ? this.heights[index - 1].accumulator : 0
526+
} else {
527+
scrollTop = index * this.itemHeight
528+
}
529+
this.scrollToPosition(scrollTop)
530+
},
531+
532+
scrollToPosition (position) {
533+
this.$el.scrollTop = position
534+
},
535+
536+
itemsLimitError () {
537+
setTimeout(() => {
538+
console.log(`It seems the scroller element isn't scrolling, so it tries to render all the items at once.`, 'Scroller:', this.$el)
539+
console.log(`Make sure the scroller has a fixed height and 'overflow-y' set to 'auto' so it can scroll correctly and only render the items visible in the scroll viewport.`)
540+
})
541+
throw new Error('Rendered items limit reached')
542+
},
369543
},
370544
}
371545
</script>

0 commit comments

Comments
 (0)