Skip to content

Instantly share code, notes, and snippets.

@maxrolon
Last active September 16, 2016 17:36
Show Gist options
  • Save maxrolon/c7515c9d540068ecb6b5e7aa00b2d72d to your computer and use it in GitHub Desktop.
Save maxrolon/c7515c9d540068ecb6b5e7aa00b2d72d to your computer and use it in GitHub Desktop.
import scroll from '../lib/scrollListener'
const Velocity = require('velocity-animate')
const fetchAnchors = el => {
let anchors = [].slice.call( el.querySelectorAll('[href]') )
return anchors.filter( restrictToHash ).map( fetchDestinations )
}
const restrictToHash = el => /#/.test( el.anchor = el.getAttribute('href') )
const fetchDestinations = el => (
{
anchor: el,
dest: document.getElementById( /.*#(.*)/.exec(el.anchor).pop() )
}
)
const reduceToClosest = scrollTop => (prev, curr) => {
//Create a new object, with the key being the offset
let obj = [prev,curr].reduce( (a,b) => (a[ Math.abs( b.dest.offsetY - scrollTop) ] = b, a), {})
let closest = Math.min( ...Object.keys(obj) )
return obj[closest]
}
const getOffset = (el, win=window, docElem=document.documentElement, box=false) => (
box = el.getBoundingClientRect(),
box.top + (win.pageYOffset || docElem.scrollTop) - (docElem.clientTop || 0)
)
const cacheOffsets = el => el.offsetY = getOffset(el)
export default function(el) {
const waypoints = fetchAnchors(el)
const sticky = el.querySelector('.js-inner')
let offset;
let getAllOffsets;
(getAllOffsets = function(){
waypoints.map(el => el.dest).forEach(cacheOffsets)
offset = getOffset(el)
})();
scroll( (scrollTop) => {
if ( scrollTop >= offset) {
sticky.classList.add('is-fixed')
} else {
sticky.classList.remove('is-fixed')
}
waypoints.forEach( el => el.anchor.classList.remove('is-active'))
waypoints.reduce( reduceToClosest(scrollTop) ).anchor.classList.add('is-active')
})
waypoints.forEach( waypoint=> {
waypoint.anchor.addEventListener('click', e => {
e.preventDefault()
e.returnValue = false
Velocity(document.body, 'scroll', {duration: 1000, offset: getOffset(waypoint.dest) - 100 })
})
})
window.addEventListener('resize', getAllOffsets)
}
@maxrolon
Copy link
Author

maxrolon commented Sep 16, 2016

A super duper simple waypoints library to handle the simple challenge of having a submenu of anchor links with ID-based href's (i.e. #Intro) that need to initiate a scroll animation to the corresponding DOM Element. See the submenu on Wanderlust 108s for an example of what I am talking about.

Dependencies
This example uses the RAFScroll library to replace window.addEventListener('scroll', function(e) {.. native usage. Replace if you want a simple but less performant option. We also use the Velocity animation library to fade in the video. Again, replace this with another form of animation if you need!

Notes

  • The module will toggle an is-fixed class to the submenu when it has reached the top of the page.
  • The module will add an is-active class to an anchor element when the user has scrolled to it's corresponding DOM Node

Usage

InitScripts initialization pattern

<div class="tabs--anchor sticky js-subnav" data-module="subNav">
  <ol class="list--reset sticky__inner clearfix js-inner">
    <li class="tab--anchor"><a href="#Order"><span class="tabs__number">1</span> Order</a></li>
    <li class="tab--anchor"><a href="#Measure"><span class="tabs__number">2</span> Measure</a></li>
    <li class="tab--anchor"><a href="#Make"><span class="tabs__number">3</span> Make &amp; Ship</a></li>
    <li class="tab--anchor"><a href="#Wear"><span class="tabs__number">4</span> Wear</a></li>
  </ol>
</div>

Vanilla Javascript initialization

import SubNav form '<./.../src>'

new SubNav( document.querySelector('.js-subnav') );

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment