Last active
January 25, 2019 13:11
-
-
Save m4n1ok/ffb2e742b3d2c958fd84ced4565471e6 to your computer and use it in GitHub Desktop.
This file contains 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
/** | |
* 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