Last active
January 15, 2020 13:43
-
-
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
This file contains hidden or 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
| /** | |
| * 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