Skip to content

Commit

Permalink
feat: add lazy option to allow recalculating targets (#388)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
RealGoodProgrammer and rigor789 authored Oct 28, 2020
1 parent 8eb93fb commit e3c70c5
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 12 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ In case you are using the browser version (directly including the script on your
VueScrollTo.setDefaults({
container: "body",
duration: 500,
lazy: false,
easing: "ease",
offset: 0,
force: true,
Expand Down Expand Up @@ -125,6 +126,7 @@ If you need to customize the scrolling options, you can pass in an object litera
el: '#element',
container: '#container',
duration: 500,
lazy: false
easing: 'linear',
offset: -200,
force: true,
Expand All @@ -151,6 +153,7 @@ var VueScrollTo = require('vue-scrollto');
var options = {
container: '#container',
easing: 'ease-in',
lazy: false,
offset: -60,
force: true,
cancelable: true,
Expand Down Expand Up @@ -196,6 +199,11 @@ The easing to be used when animating. Read more in the [Easing section](#easing-

*Default:* `ease`

#### lazy
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.

*Default:* `true`

#### offset
The offset that should be applied when scrolling. This option accepts a callback function since `v2.8.0`.

Expand Down
47 changes: 35 additions & 12 deletions src/scrollTo.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const abortEvents = [
let defaults = {
container: 'body',
duration: 500,
lazy: true,
easing: 'ease',
offset: 0,
force: true,
Expand All @@ -34,6 +35,7 @@ export const scroller = () => {
let container // container to scroll
let duration // duration of the scrolling
let easing // easing to be used when scrolling
let lazy // checks the target position at each step
let offset // offset to be added (subtracted)
let force // force scroll, even if element is visible
let cancelable // indicates if user can cancel the scroll or not.
Expand All @@ -52,6 +54,9 @@ export const scroller = () => {

let abort // is scrolling aborted

let cumulativeOffsetContainer
let cumulativeOffsetElement

let abortEv // event that aborted scrolling
let abortFn = e => {
if (!cancelable) return
Expand Down Expand Up @@ -91,10 +96,33 @@ export const scroller = () => {
return scrollLeft
}

function recalculateTargets() {
cumulativeOffsetContainer = _.cumulativeOffset(container)
cumulativeOffsetElement = _.cumulativeOffset(element)

if (x) {
targetX =
cumulativeOffsetElement.left - cumulativeOffsetContainer.left + offset
diffX = targetX - initialX
}
if (y) {
targetY =
cumulativeOffsetElement.top - cumulativeOffsetContainer.top + offset
diffY = targetY - initialY
}
}

function step(timestamp) {
if (abort) return done()
if (!timeStart) timeStart = timestamp

// When a site has a lot of media that can be loaded asynchronously,
// the targetY/targetX may end up in the wrong place during scrolling.
// So we will check this at each step
if (!lazy) {
recalculateTargets()
}

timeElapsed = timestamp - timeStart

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

container = _.$(options.container || defaults.container)
duration = options.hasOwnProperty('duration') ? options.duration : defaults.duration
duration = options.hasOwnProperty('duration')
? options.duration
: defaults.duration
lazy = options.hasOwnProperty('lazy') ? options.lazy : defaults.lazy
easing = options.easing || defaults.easing
offset = options.hasOwnProperty('offset') ? options.offset : defaults.offset
force = options.hasOwnProperty('force')
Expand All @@ -158,26 +189,18 @@ export const scroller = () => {
x = options.x === undefined ? defaults.x : options.x
y = options.y === undefined ? defaults.y : options.y

let cumulativeOffsetContainer = _.cumulativeOffset(container)
let cumulativeOffsetElement = _.cumulativeOffset(element)

if (typeof offset === 'function') {
offset = offset(element, container)
}

initialX = scrollLeft(container)
initialY = scrollTop(container)
targetY =
cumulativeOffsetElement.top - cumulativeOffsetContainer.top + offset

initialX = scrollLeft(container)
targetX =
cumulativeOffsetElement.left - cumulativeOffsetContainer.left + offset
// calculates cumulative offsets and targetX/Y + diffX/Y
recalculateTargets()

abort = false

diffY = targetY - initialY
diffX = targetX - initialX

if (!force) {
// When the container is the default (body) we need to use the viewport
// height, not the entire body height
Expand Down

0 comments on commit e3c70c5

Please sign in to comment.