Skip to content

Commit e3c70c5

Browse files
feat: add lazy option to allow recalculating targets (#388)
* feat: add dynamicPosition parameter (for dynamic container height) * fix: rename option and small refactoring * chore: apply suggestions from code review * perf: remove redundant calculation Co-authored-by: Igor Randjelovic <[email protected]>
1 parent 8eb93fb commit e3c70c5

File tree

2 files changed

+43
-12
lines changed

2 files changed

+43
-12
lines changed

README.md

+8
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ In case you are using the browser version (directly including the script on your
9898
VueScrollTo.setDefaults({
9999
container: "body",
100100
duration: 500,
101+
lazy: false,
101102
easing: "ease",
102103
offset: 0,
103104
force: true,
@@ -125,6 +126,7 @@ If you need to customize the scrolling options, you can pass in an object litera
125126
el: '#element',
126127
container: '#container',
127128
duration: 500,
129+
lazy: false
128130
easing: 'linear',
129131
offset: -200,
130132
force: true,
@@ -151,6 +153,7 @@ var VueScrollTo = require('vue-scrollto');
151153
var options = {
152154
container: '#container',
153155
easing: 'ease-in',
156+
lazy: false,
154157
offset: -60,
155158
force: true,
156159
cancelable: true,
@@ -196,6 +199,11 @@ The easing to be used when animating. Read more in the [Easing section](#easing-
196199

197200
*Default:* `ease`
198201

202+
#### lazy
203+
By default targetX/targetY are calculated once at the start of a scroll, however if the target may shift around during the scroll - setting `lazy` to `false` will force recalculation of targetX/targetY at each scroll step.
204+
205+
*Default:* `true`
206+
199207
#### offset
200208
The offset that should be applied when scrolling. This option accepts a callback function since `v2.8.0`.
201209

src/scrollTo.js

+35-12
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const abortEvents = [
1414
let defaults = {
1515
container: 'body',
1616
duration: 500,
17+
lazy: true,
1718
easing: 'ease',
1819
offset: 0,
1920
force: true,
@@ -34,6 +35,7 @@ export const scroller = () => {
3435
let container // container to scroll
3536
let duration // duration of the scrolling
3637
let easing // easing to be used when scrolling
38+
let lazy // checks the target position at each step
3739
let offset // offset to be added (subtracted)
3840
let force // force scroll, even if element is visible
3941
let cancelable // indicates if user can cancel the scroll or not.
@@ -52,6 +54,9 @@ export const scroller = () => {
5254

5355
let abort // is scrolling aborted
5456

57+
let cumulativeOffsetContainer
58+
let cumulativeOffsetElement
59+
5560
let abortEv // event that aborted scrolling
5661
let abortFn = e => {
5762
if (!cancelable) return
@@ -91,10 +96,33 @@ export const scroller = () => {
9196
return scrollLeft
9297
}
9398

99+
function recalculateTargets() {
100+
cumulativeOffsetContainer = _.cumulativeOffset(container)
101+
cumulativeOffsetElement = _.cumulativeOffset(element)
102+
103+
if (x) {
104+
targetX =
105+
cumulativeOffsetElement.left - cumulativeOffsetContainer.left + offset
106+
diffX = targetX - initialX
107+
}
108+
if (y) {
109+
targetY =
110+
cumulativeOffsetElement.top - cumulativeOffsetContainer.top + offset
111+
diffY = targetY - initialY
112+
}
113+
}
114+
94115
function step(timestamp) {
95116
if (abort) return done()
96117
if (!timeStart) timeStart = timestamp
97118

119+
// When a site has a lot of media that can be loaded asynchronously,
120+
// the targetY/targetX may end up in the wrong place during scrolling.
121+
// So we will check this at each step
122+
if (!lazy) {
123+
recalculateTargets()
124+
}
125+
98126
timeElapsed = timestamp - timeStart
99127

100128
progress = Math.min(timeElapsed / duration, 1)
@@ -143,7 +171,10 @@ export const scroller = () => {
143171
}
144172

145173
container = _.$(options.container || defaults.container)
146-
duration = options.hasOwnProperty('duration') ? options.duration : defaults.duration
174+
duration = options.hasOwnProperty('duration')
175+
? options.duration
176+
: defaults.duration
177+
lazy = options.hasOwnProperty('lazy') ? options.lazy : defaults.lazy
147178
easing = options.easing || defaults.easing
148179
offset = options.hasOwnProperty('offset') ? options.offset : defaults.offset
149180
force = options.hasOwnProperty('force')
@@ -158,26 +189,18 @@ export const scroller = () => {
158189
x = options.x === undefined ? defaults.x : options.x
159190
y = options.y === undefined ? defaults.y : options.y
160191

161-
let cumulativeOffsetContainer = _.cumulativeOffset(container)
162-
let cumulativeOffsetElement = _.cumulativeOffset(element)
163-
164192
if (typeof offset === 'function') {
165193
offset = offset(element, container)
166194
}
167195

196+
initialX = scrollLeft(container)
168197
initialY = scrollTop(container)
169-
targetY =
170-
cumulativeOffsetElement.top - cumulativeOffsetContainer.top + offset
171198

172-
initialX = scrollLeft(container)
173-
targetX =
174-
cumulativeOffsetElement.left - cumulativeOffsetContainer.left + offset
199+
// calculates cumulative offsets and targetX/Y + diffX/Y
200+
recalculateTargets()
175201

176202
abort = false
177203

178-
diffY = targetY - initialY
179-
diffX = targetX - initialX
180-
181204
if (!force) {
182205
// When the container is the default (body) we need to use the viewport
183206
// height, not the entire body height

0 commit comments

Comments
 (0)