Skip to content

Commit 4fb72fd

Browse files
committed
Support scrollToBottom
1 parent 2f12958 commit 4fb72fd

File tree

1 file changed

+38
-23
lines changed

1 file changed

+38
-23
lines changed

src/index.js

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -92,37 +92,52 @@ const VirtualList = Vue.component(NAME, {
9292
this.scrollToOffset(0)
9393
} else if (index >= this.dataSources.length - 1) {
9494
// scroll to bottom
95-
this.scrollToOffset(this.getScrollSize())
95+
this.scrollToBottom()
9696
} else {
9797
const offset = this.virtual.getOffset(index)
9898
this.scrollToOffset(offset)
9999
}
100100
},
101101

102+
// set current scroll position to bottom
103+
scrollToBottom () {
104+
const { shepherd } = this.$refs
105+
if (shepherd) {
106+
shepherd.scrollIntoView(false)
107+
108+
// check if it's really scrolled to the bottom
109+
// maybe list doesn't render and calculate to last range
110+
// so we need retry in next event loop until it really at bottom
111+
setTimeout(() => {
112+
if (this.getOffset() + this.getClientSize() < this.getScrollSize()) {
113+
this.scrollToBottom()
114+
}
115+
}, 3);
116+
}
117+
},
118+
102119
// ----------- public method end -----------
103120

104121
getUniqueIdFromDataSources () {
105122
return this.dataSources.map((dataSource) => dataSource[this.dataKey])
106123
},
107124

108-
// get client viewport size (width or height)
125+
// return current scroll offset
126+
getOffset () {
127+
const { root } = this.$refs
128+
return root ? root[this.directionKey] : 0
129+
},
130+
131+
// return client viewport size (width or height)
109132
getClientSize () {
110133
const { root } = this.$refs
111-
if (root) {
112-
return root[this.isHorizontal ? 'clientWidth' : 'clientHeight']
113-
} else {
114-
return 0
115-
}
134+
return root ? root[this.isHorizontal ? 'clientWidth' : 'clientHeight'] : 0
116135
},
117136

118-
// get all scroll size (width or height)
137+
// return all scroll size (width or height)
119138
getScrollSize () {
120139
const { root } = this.$refs
121-
if (root) {
122-
return root[this.isHorizontal ? 'scrollWidth' : 'scrollHeight']
123-
} else {
124-
return 0
125-
}
140+
return root ? root[this.isHorizontal ? 'scrollWidth' : 'scrollHeight'] : 0
126141
},
127142

128143
// event called when each item mounted or size changed
@@ -149,17 +164,12 @@ const VirtualList = Vue.component(NAME, {
149164
},
150165

151166
onScroll (evt) {
152-
const { root } = this.$refs
153-
if (!root) {
154-
return
155-
}
156-
157-
const offset = root[this.directionKey]
167+
const offset = this.getOffset()
158168
const clientSize = this.getClientSize()
159169
const scrollSize = this.getScrollSize()
160170

161171
// iOS scroll-spring-back behavior will make direction mistake
162-
if (offset + clientSize > scrollSize) {
172+
if (offset + clientSize > scrollSize || !scrollSize) {
163173
return
164174
}
165175

@@ -170,9 +180,9 @@ const VirtualList = Vue.component(NAME, {
170180
// emit event in special position
171181
emitEvent (offset, clientSize, scrollSize, evt) {
172182
const range = this.virtual.getRange()
173-
if (this.virtual.isFront() && !!this.dataSources.length && offset - this.topThreshold <= 0) {
183+
if (this.virtual.isFront() && !!this.dataSources.length && (offset - this.topThreshold <= 0)) {
174184
this.$emit('totop', evt, range)
175-
} else if (this.virtual.isBehind() && offset + clientSize + this.bottomThreshold >= scrollSize) {
185+
} else if (this.virtual.isBehind() && (offset + clientSize + this.bottomThreshold >= scrollSize)) {
176186
this.$emit('tobottom', evt, range)
177187
} else {
178188
this.$emit('scroll', evt, range)
@@ -250,7 +260,12 @@ const VirtualList = Vue.component(NAME, {
250260
event: EVENT_TYPE.SLOT,
251261
uniqueKey: SLOT_TYPE.FOOTER
252262
}
253-
}, footer) : null
263+
}, footer) : null,
264+
265+
// an empty element use to scroll to bottom
266+
h('div', {
267+
ref: 'shepherd'
268+
})
254269
])
255270
}
256271
})

0 commit comments

Comments
 (0)