Skip to content

Instantly share code, notes, and snippets.

@m4n1ok
Last active January 25, 2019 13:11
Show Gist options
  • Save m4n1ok/ffb2e742b3d2c958fd84ced4565471e6 to your computer and use it in GitHub Desktop.
Save m4n1ok/ffb2e742b3d2c958fd84ced4565471e6 to your computer and use it in GitHub Desktop.
/**
* ScrollDirection
* Simple Singleton to listen scrollDirection
* Use an array of callbacks objects running when user scroll to top or to down
* Could be usefull to pin header on scroll top for example
*/
class ScrollDirection {
constructor () {
if (!ScrollDirection.instance) {
this._isRunning = false
this._callbacksMap = {}
this._callbacks = []
this.lastKnownScrollY = 0
this._currentScrollY = 0
this._ticking = false
ScrollDirection.instance = this
}
return ScrollDirection.instance
}
onScroll () {
this._currentScrollY = window.pageYOffset
this.requestTick()
}
requestTick () {
if (!this._ticking) {
window.requestAnimationFrame(this.update.bind(this))
}
this._ticking = true
}
update () {
if (this._currentScrollY < this.lastKnownScrollY) {
this.top()
} else if (this._currentScrollY > this.lastKnownScrollY) {
this.bottom()
}
this.lastKnownScrollY = this._currentScrollY
this._ticking = false
}
/**
* Default top method
* Call all callbacks top methods and pass scrollPosition as param
*/
top () {
this._callbacks.forEach(callback => {
callback.top(this.lastKnownScrollY)
})
}
/**
* Default bottom method
* Call all callbacks bottom methods and pass scrollPosition as param
*/
bottom () {
this._callbacks.forEach(callback => {
callback.bottom(this.lastKnownScrollY)
})
}
run () {
this._isRunning = true
window.addEventListener('scroll', this.onScroll.bind(this), false)
}
stop () {
this._isRunning = false
window.removeEventListener('scroll', this.onScroll.bind(this), false)
}
/**
* Add Method
* @param callback, an object with top and down method
* @returns Number, a timestamp corresponding to id of callback
*/
add (callback) {
if (typeof callback !== 'object' && !('top' in callback) && !('bottom' in callback)) return false
const index = Date.now()
this._callbacksMap[index] = callback
this._callbacks = Object.values(this._callbacksMap)
if (this._isRunning) return index
this.run()
return index
}
/**
* Remove Method
* Pass an id of callback as param
* @param id
* @returns {null}
*/
remove (id) {
if (!this._callbacksMap[id]) return
delete this._callbacksMap[id]
this._callbacks = Object.values(this._callbacksMap)
if (this._callbacks.length === 0) {
this.stop()
}
return null
}
destroy () {
this._callbacks = []
this._callbacksMap = {}
}
}
const instance = new ScrollDirection()
export default instance
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment