-
Notifications
You must be signed in to change notification settings - Fork 434
/
scroll-spy.js
89 lines (70 loc) · 3.22 KB
/
scroll-spy.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import throttle from "lodash.throttle";
import { addPassiveEventListener, removePassiveEventListener } from './passive-event-listeners';
// The eventHandler will execute at a rate of 15fps by default
const eventThrottler = (eventHandler, throttleAmount = 66) => throttle(eventHandler, throttleAmount);
const scrollSpy = {
spyCallbacks: [],
spySetState: [],
scrollSpyContainers: [],
mount(scrollSpyContainer, throttle) {
if (scrollSpyContainer) {
const eventHandler = eventThrottler((event) => {
scrollSpy.scrollHandler(scrollSpyContainer);
}, throttle);
scrollSpy.scrollSpyContainers.push(scrollSpyContainer);
addPassiveEventListener(scrollSpyContainer, 'scroll', eventHandler);
return () => removePassiveEventListener(scrollSpyContainer, 'scroll', eventHandler);
}
return () => {};
},
isMounted(scrollSpyContainer) {
return scrollSpy.scrollSpyContainers.indexOf(scrollSpyContainer) !== -1;
},
currentPositionX(scrollSpyContainer) {
if(scrollSpyContainer === document) {
let supportPageOffset = window.pageYOffset !== undefined;
let isCSS1Compat = ((document.compatMode || "") === "CSS1Compat");
return supportPageOffset ? window.pageXOffset : isCSS1Compat ?
document.documentElement.scrollLeft : document.body.scrollLeft;
} else {
return scrollSpyContainer.scrollLeft;
}
},
currentPositionY(scrollSpyContainer) {
if(scrollSpyContainer === document) {
let supportPageOffset = window.pageXOffset !== undefined;
let isCSS1Compat = ((document.compatMode || "") === "CSS1Compat");
return supportPageOffset ? window.pageYOffset : isCSS1Compat ?
document.documentElement.scrollTop : document.body.scrollTop;
} else {
return scrollSpyContainer.scrollTop;
}
},
scrollHandler(scrollSpyContainer) {
let callbacks = scrollSpy.scrollSpyContainers[scrollSpy.scrollSpyContainers.indexOf(scrollSpyContainer)].spyCallbacks || [];
callbacks.forEach(c => c(scrollSpy.currentPositionX(scrollSpyContainer), scrollSpy.currentPositionY(scrollSpyContainer)));
},
addStateHandler(handler) {
scrollSpy.spySetState.push(handler);
},
addSpyHandler(handler, scrollSpyContainer) {
let container = scrollSpy.scrollSpyContainers[scrollSpy.scrollSpyContainers.indexOf(scrollSpyContainer)];
if(!container.spyCallbacks) {
container.spyCallbacks = [];
}
container.spyCallbacks.push(handler);
handler(scrollSpy.currentPositionX(scrollSpyContainer), scrollSpy.currentPositionY(scrollSpyContainer));
},
updateStates() {
scrollSpy.spySetState.forEach(s => s());
},
unmount(stateHandler, spyHandler) {
scrollSpy.scrollSpyContainers.forEach(c => c.spyCallbacks && c.spyCallbacks.length && c.spyCallbacks.indexOf(spyHandler) > -1 && c.spyCallbacks.splice(c.spyCallbacks.indexOf(spyHandler), 1))
if(scrollSpy.spySetState && scrollSpy.spySetState.length && scrollSpy.spySetState.indexOf(stateHandler) > -1) {
scrollSpy.spySetState.splice(scrollSpy.spySetState.indexOf(stateHandler), 1);
}
document.removeEventListener('scroll', scrollSpy.scrollHandler);
},
update: () => scrollSpy.scrollSpyContainers.forEach(c => scrollSpy.scrollHandler(c))
}
export default scrollSpy;