-
Notifications
You must be signed in to change notification settings - Fork 2
/
v-scroll-sync.js
78 lines (71 loc) · 2.52 KB
/
v-scroll-sync.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
/**
* Vue plugin that adds the directive v-scroll-sync.
*
* <div v-scroll-sync>
*
* v-scroll-sync optionally lets you specify a group the elements to scroll
* together. All ungrouped elements are grouped together.
*
* <div v-scroll-sync:group1>
*
* It also supports two modifiers, .x and .y, if you want to only sync
* scrolling on one of those two axis. It defaults to both.
*
* <div v-scroll-sync:group1.x>
*/
const VScrollSync = {
install(Vue, options) {
const groups = {};
let isScrolling = false;
let elements = (group, modifiers, e) => {
if (e) {
if (!(group in groups)) {
groups[group] = [];
}
groups[group].push({ modifiers, e });
}
return groups[group];
};
const scrollSync = {
bind(el, {
arg: group,
modifiers,
value: applyScroll = (element, target, { x, y }) => {
if (y) {
target.scrollTop = element.scrollTop
* (target.scrollHeight - target.clientHeight)
/ (element.scrollHeight - element.clientHeight);
}
if (x) {
target.scrollLeft = element.scrollLeft
* (target.scrollWidth - target.clientWidth)
/ (element.scrollWidth - element.clientWidth);
}
},
}) {
if (!('x' in modifiers || 'y' in modifiers)) {
modifiers.x = true;
modifiers.y = true;
}
elements(group, modifiers, el);
el.addEventListener('scroll', () => {
if (!isScrolling) {
isScrolling = true;
requestAnimationFrame(() => {
elements(group)
.filter(({ e }) => e !== el)
.forEach(({ modifiers, e }) => {
applyScroll(el, e, modifiers);
});
requestAnimationFrame(() => {
isScrolling = false;
});
});
}
});
},
};
Vue.directive('scroll-sync', scrollSync);
},
};
export default VScrollSync;