import React from 'react'; import PropTypes from 'prop-types'; const elClassHidden = 'header--hidden'; const elClassBackground = 'header--background'; export default class Header extends React.Component { constructor(props) { super(props); this.dHeight = 0; this.wHeight = 0; this.wScrollCurrent = 0; this.wScrollBefore = 0; this.wScrollDiff = 0; this.header = React.createRef(); } componentDidMount() { window.addEventListener('scroll', () => (!window.requestAnimationFrame) ? this.throttle(250, this.updateHeader) : window.requestAnimationFrame(this.updateHeader), false); } throttle(delay, fn) { var last, deferTimer; return function () { var context = this, args = arguments, now = +new Date; if (last && now < last + delay) { clearTimeout(deferTimer); deferTimer = setTimeout( function () { last = now; fn.apply(context, args); }, delay); } else { last = now; fn.apply(context, args); } }; } updateHeader = () => { const header = this.header.current; this.dHeight = document.body.offsetHeight; this.wHeight = window.innerHeight; this.wScrollCurrent = window.pageYOffset; this.wScrollDiff = this.wScrollBefore - this.wScrollCurrent; if (this.wScrollCurrent <= 0) { // scrolled to the very top; element sticks to the top header.classList.remove(elClassHidden); header.classList.remove(elClassBackground); } else if (this.wScrollDiff > 0 && header.classList.contains(elClassHidden)) { // scrolled up; element slides in header.classList.remove(elClassHidden); header.classList.add(elClassBackground); } else if (this.wScrollDiff < 0) { // scrolled down if (this.wScrollCurrent + this.wHeight >= this.dHeight && header.classList.contains(elClassHidden)) { // scrolled to the very bottom; element slides in header.classList.remove(elClassHidden); header.classList.add(elClassBackground); } else { // scrolled down; element slides out header.classList.add(elClassHidden); } } this.wScrollBefore = this.wScrollCurrent; } render() { return (); } } Header.propTypes = { children: PropTypes.node, style: PropTypes.style };