Skip to content

Commit 11546d8

Browse files
committed
feat: resize observer + undefinedSizes cleaner code
1 parent 95ce62e commit 11546d8

File tree

2 files changed

+93
-29
lines changed

2 files changed

+93
-29
lines changed

src/components/DynamicScroller.vue

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,28 @@ export default {
4343
inheritAttrs: false,
4444
4545
provide () {
46+
if (typeof ResizeObserver !== 'undefined') {
47+
this.$_resizeObserver = new ResizeObserver(entries => {
48+
for (const entry of entries) {
49+
if (entry.target) {
50+
const event = new CustomEvent(
51+
'resize',
52+
{
53+
detail: {
54+
contentRect: entry.contentRect,
55+
},
56+
},
57+
)
58+
entry.target.dispatchEvent(event)
59+
}
60+
}
61+
})
62+
}
63+
4664
return {
4765
vscrollData: this.vscrollData,
4866
vscrollParent: this,
67+
vscrollResizeObserver: this.$_resizeObserver,
4968
}
5069
},
5170
@@ -82,10 +101,6 @@ export default {
82101
const id = simpleArray ? i : item[keyField]
83102
let size = sizes[id]
84103
if (typeof size === 'undefined' && !this.$_undefinedMap[id]) {
85-
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
86-
this.$_undefinedSizes++
87-
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
88-
this.$_undefinedMap[id] = true
89104
size = 0
90105
}
91106
result.push({
@@ -176,14 +191,18 @@ export default {
176191
const el = this.$el
177192
// Item is inserted to the DOM
178193
this.$nextTick(() => {
194+
el.scrollTop = Number.MAX_SAFE_INTEGER
179195
// Item sizes are computed
180196
const cb = () => {
181-
el.scrollTop = el.scrollHeight
182-
if (this.$_undefinedSizes === 0) {
183-
this.$_scrollingToBottom = false
184-
} else {
185-
requestAnimationFrame(cb)
186-
}
197+
el.scrollTop = Number.MAX_SAFE_INTEGER
198+
requestAnimationFrame(() => {
199+
el.scrollTop = Number.MAX_SAFE_INTEGER
200+
if (this.$_undefinedSizes === 0) {
201+
this.$_scrollingToBottom = false
202+
} else {
203+
requestAnimationFrame(cb)
204+
}
205+
})
187206
}
188207
requestAnimationFrame(cb)
189208
})

src/components/DynamicScrollerItem.vue

Lines changed: 64 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ export default {
55
inject: [
66
'vscrollData',
77
'vscrollParent',
8+
'vscrollResizeObserver',
89
],
910
1011
props: {
@@ -63,9 +64,31 @@ export default {
6364
},
6465
6566
active (value) {
67+
if (!this.size) {
68+
if (value) {
69+
if (!this.vscrollParent.$_undefinedMap[this.id]) {
70+
this.vscrollParent.$_undefinedSizes++
71+
this.vscrollParent.$_undefinedMap[this.id] = true
72+
}
73+
} else {
74+
if (this.vscrollParent.$_undefinedMap[this.id]) {
75+
this.vscrollParent.$_undefinedSizes--
76+
this.vscrollParent.$_undefinedMap[this.id] = false
77+
}
78+
}
79+
}
80+
6681
if (value && this.$_pendingVScrollUpdate === this.id) {
6782
this.updateSize()
6883
}
84+
85+
if (this.vscrollResizeObserver) {
86+
if (value) {
87+
this.observeSize()
88+
} else {
89+
this.unobserveSize()
90+
}
91+
}
6992
},
7093
},
7194
@@ -75,23 +98,27 @@ export default {
7598
this.$_forceNextVScrollUpdate = null
7699
this.updateWatchData()
77100
78-
for (const k in this.sizeDependencies) {
79-
this.$watch(() => this.sizeDependencies[k], this.onDataUpdate)
80-
}
101+
if (!this.vscrollResizeObserver) {
102+
for (const k in this.sizeDependencies) {
103+
this.$watch(() => this.sizeDependencies[k], this.onDataUpdate)
104+
}
81105
82-
this.vscrollParent.$on('vscroll:update', this.onVscrollUpdate)
83-
this.vscrollParent.$on('vscroll:update-size', this.onVscrollUpdateSize)
106+
this.vscrollParent.$on('vscroll:update', this.onVscrollUpdate)
107+
this.vscrollParent.$on('vscroll:update-size', this.onVscrollUpdateSize)
108+
}
84109
},
85110
86111
mounted () {
87112
if (this.vscrollData.active) {
88113
this.updateSize()
114+
this.observeSize()
89115
}
90116
},
91117
92118
beforeDestroy () {
93119
this.vscrollParent.$off('vscroll:update', this.onVscrollUpdate)
94120
this.vscrollParent.$off('vscroll:update-size', this.onVscrollUpdateSize)
121+
this.unobserveSize()
95122
},
96123
97124
methods: {
@@ -137,26 +164,44 @@ export default {
137164
},
138165
139166
computeSize (id) {
167+
if (this.vscrollResizeObserver) return
140168
this.$nextTick(() => {
141169
if (this.id === id) {
142-
const bounds = {
143-
width: this.$el.offsetWidth,
144-
height: this.$el.offsetHeight,
145-
}
146-
const size = Math.round(this.vscrollParent.direction === 'vertical' ? bounds.height : bounds.width)
147-
if (size && this.size !== size) {
148-
if (this.vscrollParent.$_undefinedMap[id]) {
149-
this.vscrollParent.$_undefinedSizes--
150-
this.vscrollParent.$_undefinedMap[id] = undefined
151-
}
152-
this.$set(this.vscrollData.sizes, this.id, size)
153-
this.$set(this.vscrollData.validSizes, this.id, true)
154-
if (this.emitResize) this.$emit('resize', this.id)
155-
}
170+
const width = this.$el.offsetWidth
171+
const height = this.$el.offsetHeight
172+
this.applySize(width, height)
156173
}
157174
this.$_pendingSizeUpdate = null
158175
})
159176
},
177+
178+
applySize (width, height) {
179+
const size = Math.round(this.vscrollParent.direction === 'vertical' ? height : width)
180+
if (size && this.size !== size) {
181+
if (this.vscrollParent.$_undefinedMap[this.id]) {
182+
this.vscrollParent.$_undefinedSizes--
183+
this.vscrollParent.$_undefinedMap[this.id] = undefined
184+
}
185+
this.$set(this.vscrollData.sizes, this.id, size)
186+
this.$set(this.vscrollData.validSizes, this.id, true)
187+
if (this.emitResize) this.$emit('resize', this.id)
188+
}
189+
},
190+
191+
observeSize () {
192+
this.vscrollResizeObserver.observe(this.$el.parentNode)
193+
this.$el.parentNode.addEventListener('resize', this.onResize)
194+
},
195+
196+
unobserveSize () {
197+
this.vscrollResizeObserver.unobserve(this.$el.parentNode)
198+
this.$el.parentNode.removeEventListener('resize', this.onResize)
199+
},
200+
201+
onResize (event) {
202+
const { width, height } = event.detail.contentRect
203+
this.applySize(width, height)
204+
},
160205
},
161206
162207
render (h) {

0 commit comments

Comments
 (0)