Skip to content

Instantly share code, notes, and snippets.

@wuhhh
Last active January 15, 2020 13:43
Show Gist options
  • Save wuhhh/78a9fadcff7da55b66ea09cd1b6d9499 to your computer and use it in GitHub Desktop.
Save wuhhh/78a9fadcff7da55b66ea09cd1b6d9499 to your computer and use it in GitHub Desktop.
A simple parallax plugin for Vue. Add the v-parallax directive to elements you want to... parallaxify. Directive argument should be an object with single argument, 'target'. Target specifies the final offset amount (in px) for the element
/**
* A simple parallax plugin for Vue
* Add the v-parallax directive to elements you want to... parallaxify.
* Directive argument should be an object with single argument, 'target'
* Target specifies the final offset amount (in px) for the element
*
* For example:
*
* <my-element v-parallax="{ target: -500 }">
*/
import Vue from 'vue'
const Parallax = {}
Parallax.install = function(Vue, options) {
let parallaxEls = []
let scrollY = window.scrollY
/**
*
* @param {*} n
* @param {*} inMin
* @param {*} inMax
* @param {*} outMin
* @param {*} outMax
*/
const map = (n, inMin, inMax, outMin, outMax) => {
return ((n - inMin) * (outMax - outMin)) / (inMax - inMin) + outMin
}
/**
*
* @param {*} fn
* @param {*} wait
*/
const throttle = (fn, wait) => {
let time = Date.now()
return function() {
if (time + wait - Date.now() < 0) {
fn()
time = Date.now()
}
}
}
/**
* Get elements
*/
const getParallaxEls = () => {
parallaxEls = null
setTimeout(() => {
parallaxEls = document.querySelectorAll('[data-parallax]')
}, 250)
}
/**
* Add el
*/
const addEl = (el, config) => {
// Add class if specified in options
if (options.addClass) {
el.classList.add(options.addClass)
}
// Push to array
parallaxEls.push({
el,
config
})
}
/**
* Parallaxify
*/
const parallaxify = () => {
if (parallaxEls) {
const scrollHeight = document.body.scrollHeight
const windowInner = window.innerHeight
const inMax = scrollHeight - windowInner
parallaxEls.forEach((el) => {
const prlxTarget = el.config.target
const mapped = map(
scrollY,
0,
inMax,
-prlxTarget / 2,
prlxTarget / 2
).toFixed(2)
el.el.setAttribute('style', `transform: translateY(${mapped}px)`)
})
}
window.requestAnimationFrame(parallaxify)
}
/**
* Scroll callback
*/
const handleScroll = () => {
scrollY = window.scrollY
}
// Init
window.requestAnimationFrame(parallaxify)
window.addEventListener('scroll', throttle(handleScroll, 100))
// Add a directive
Vue.directive('parallax', {
bind(el, binding, vnode, oldVnode) {
addEl(el, binding.value)
}
})
// Inject component options
Vue.mixin({
watch: {
$route() {
// Reset els on route change
parallaxEls = []
}
}
})
}
Vue.use(Parallax, {
addClass: '--parallax'
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment