Created
October 17, 2019 12:47
-
-
Save johndigital/32b4c1b80ce12180c10f6d487f53cc8f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div class="scrolling-layout"> | |
<!-- This is just an 800vh spacer, | |
it ensures the page is tall | |
enough to scroll --> | |
<div class="spacer" /> | |
<!-- This is the actual content that gets scrolled. | |
It is position fixed and the "scrolling" is done | |
with transforms --> | |
<transition name="fade"> | |
<div v-show="ready" class="slider" :style="sliderStyle"> | |
<flex-layout :layout="layout" /> | |
<flex-layout :layout="layout" /> | |
<flex-layout :layout="layout" /> | |
</div> | |
</transition> | |
</div> | |
</template> | |
<script> | |
import { everyFrame, transform, value, listen } from 'popmotion' | |
const { wrap, clamp, smooth } = transform | |
const wrapper = wrap(0, 1) | |
const clamper = clamp(-1, 1) | |
let scrollPos | |
export default { | |
data() { | |
return { | |
ready: false, | |
scrollListener: null, | |
tickAction: null, | |
direction: 1, | |
looped: 0, | |
yPos: 0, | |
sTop: 0 | |
} | |
}, | |
async mounted() { | |
// Set up scroll listener to keep track of window scrollTop | |
this.scrollListener = listen(window, 'scroll').start(() => { | |
this.sTop = window.pageYOffset || document.documentElement.scrollTop | |
}) | |
// Kick the endless scroll function | |
// (looping back to middle using window.scrollTo) | |
this.startEndlessScroll() | |
// allow the page to render | |
await this.$nextTick() | |
// Start tracking the velocity of the scrollDist, | |
// which is just a measurement of how many pixels the | |
// user has scrolled in total including the loops | |
scrollPos = value(this.scrollDist) | |
// Start an animation tick every frame | |
this.tickAction = everyFrame() | |
.pipe( | |
() => { | |
// Feed the overall scrolling distance | |
// into a smoothing fucntion every tick | |
return this.scrollDist | |
}, | |
// This number controls how smoothed | |
// out the scroll motion is. | |
smooth(150) | |
) | |
.start(scrollDist => { | |
// Update the scroll distance tracker with the smoothed | |
// value so we can track velocity | |
scrollPos.update(scrollDist) | |
// Convert velocity into a useful multiplier value | |
// that we can use to actually move the page | |
const vel = scrollPos.getVelocity() * 0.06 | |
// Ensure it is clamped between -1 and 1 | |
const mult = clamper(vel / 1000) | |
// Keep track of direction change. | |
// At this point if mult is negative the user | |
// is scrolling up and vice versa | |
if (this.direction === 1 && mult < -0.01) { | |
this.direction = -1 | |
} else if (this.direction === -1 && mult > 0.01) { | |
this.direction = 1 | |
} | |
// Apply movement. | |
// yPos is a fraction between 0 and 1 that represents how | |
// scrolled the page is with 1 being 100% | |
const movement = 0.0004 * this.direction + 0.03 * mult | |
this.yPos = wrapper(this.yPos + movement) | |
}) | |
this.ready = true | |
}, | |
beforeDestroy() { | |
// Tear down all listeners when we move off the page | |
if (this.scrollListener) this.scrollListener.stop() | |
if (this.tickAction) this.tickAction.stop() | |
window.removeEventListener('scroll', this.trackScrollJump) | |
}, | |
computed: { | |
page() { | |
return _get(this.$store.state, 'pageData.frontpage') | |
}, | |
layout() { | |
return _get(this.page, 'acf.layout') || [] | |
}, | |
midPoint() { | |
// This keeps track of where the middle of the document is | |
const { docHeight, winHeight } = this.$store.state.browser | |
return docHeight / 2 - winHeight / 2 | |
}, | |
sliderStyle() { | |
return { | |
transform: `translateY(-${33.33 + 33.33 * this.yPos}%)` | |
} | |
}, | |
scrollDist() { | |
return this.sTop - this.midPoint + this.looped * this.midPoint | |
} | |
}, | |
methods: { | |
startEndlessScroll() { | |
// Set scroll to middle of page | |
this.scrollToMiddle() | |
window.addEventListener('scroll', this.trackScrollJump) | |
}, | |
trackScrollJump() { | |
const { docHeight, winHeight } = this.$store.state.browser | |
if (this.sTop <= 100) { | |
this.scrollToMiddle() | |
this.looped-- | |
} else if (this.sTop >= docHeight - winHeight - 100) { | |
this.scrollToMiddle() | |
this.looped++ | |
} | |
}, | |
scrollToMiddle() { | |
window.scrollTo(0, this.midPoint) | |
this.sTop = this.midPoint | |
} | |
} | |
} | |
</script> | |
<style lang="scss"> | |
.scrolling-layout { | |
.slider { | |
position: fixed; | |
right: 0; | |
left: 0; | |
top: 0; | |
} | |
.spacer { | |
height: 800vh; | |
} | |
} | |
</style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment