UNPKG

10.4 kBJavaScriptView Raw
1import { getDocument } from 'ssr-window';
2import $ from '../../shared/dom.js';
3import { nextTick } from '../../shared/utils.js';
4import createElementIfNotDefined from '../../shared/create-element-if-not-defined.js';
5export default function Scrollbar({
6 swiper,
7 extendParams,
8 on,
9 emit
10}) {
11 const document = getDocument();
12 let isTouched = false;
13 let timeout = null;
14 let dragTimeout = null;
15 let dragStartPos;
16 let dragSize;
17 let trackSize;
18 let divider;
19 extendParams({
20 scrollbar: {
21 el: null,
22 dragSize: 'auto',
23 hide: false,
24 draggable: false,
25 snapOnRelease: true,
26 lockClass: 'swiper-scrollbar-lock',
27 dragClass: 'swiper-scrollbar-drag',
28 scrollbarDisabledClass: 'swiper-scrollbar-disabled',
29 horizontalClass: `swiper-scrollbar-horizontal`,
30 verticalClass: `swiper-scrollbar-vertical`
31 }
32 });
33 swiper.scrollbar = {
34 el: null,
35 dragEl: null,
36 $el: null,
37 $dragEl: null
38 };
39
40 function setTranslate() {
41 if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;
42 const {
43 scrollbar,
44 rtlTranslate: rtl,
45 progress
46 } = swiper;
47 const {
48 $dragEl,
49 $el
50 } = scrollbar;
51 const params = swiper.params.scrollbar;
52 let newSize = dragSize;
53 let newPos = (trackSize - dragSize) * progress;
54
55 if (rtl) {
56 newPos = -newPos;
57
58 if (newPos > 0) {
59 newSize = dragSize - newPos;
60 newPos = 0;
61 } else if (-newPos + dragSize > trackSize) {
62 newSize = trackSize + newPos;
63 }
64 } else if (newPos < 0) {
65 newSize = dragSize + newPos;
66 newPos = 0;
67 } else if (newPos + dragSize > trackSize) {
68 newSize = trackSize - newPos;
69 }
70
71 if (swiper.isHorizontal()) {
72 $dragEl.transform(`translate3d(${newPos}px, 0, 0)`);
73 $dragEl[0].style.width = `${newSize}px`;
74 } else {
75 $dragEl.transform(`translate3d(0px, ${newPos}px, 0)`);
76 $dragEl[0].style.height = `${newSize}px`;
77 }
78
79 if (params.hide) {
80 clearTimeout(timeout);
81 $el[0].style.opacity = 1;
82 timeout = setTimeout(() => {
83 $el[0].style.opacity = 0;
84 $el.transition(400);
85 }, 1000);
86 }
87 }
88
89 function setTransition(duration) {
90 if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;
91 swiper.scrollbar.$dragEl.transition(duration);
92 }
93
94 function updateSize() {
95 if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;
96 const {
97 scrollbar
98 } = swiper;
99 const {
100 $dragEl,
101 $el
102 } = scrollbar;
103 $dragEl[0].style.width = '';
104 $dragEl[0].style.height = '';
105 trackSize = swiper.isHorizontal() ? $el[0].offsetWidth : $el[0].offsetHeight;
106 divider = swiper.size / (swiper.virtualSize + swiper.params.slidesOffsetBefore - (swiper.params.centeredSlides ? swiper.snapGrid[0] : 0));
107
108 if (swiper.params.scrollbar.dragSize === 'auto') {
109 dragSize = trackSize * divider;
110 } else {
111 dragSize = parseInt(swiper.params.scrollbar.dragSize, 10);
112 }
113
114 if (swiper.isHorizontal()) {
115 $dragEl[0].style.width = `${dragSize}px`;
116 } else {
117 $dragEl[0].style.height = `${dragSize}px`;
118 }
119
120 if (divider >= 1) {
121 $el[0].style.display = 'none';
122 } else {
123 $el[0].style.display = '';
124 }
125
126 if (swiper.params.scrollbar.hide) {
127 $el[0].style.opacity = 0;
128 }
129
130 if (swiper.params.watchOverflow && swiper.enabled) {
131 scrollbar.$el[swiper.isLocked ? 'addClass' : 'removeClass'](swiper.params.scrollbar.lockClass);
132 }
133 }
134
135 function getPointerPosition(e) {
136 if (swiper.isHorizontal()) {
137 return e.type === 'touchstart' || e.type === 'touchmove' ? e.targetTouches[0].clientX : e.clientX;
138 }
139
140 return e.type === 'touchstart' || e.type === 'touchmove' ? e.targetTouches[0].clientY : e.clientY;
141 }
142
143 function setDragPosition(e) {
144 const {
145 scrollbar,
146 rtlTranslate: rtl
147 } = swiper;
148 const {
149 $el
150 } = scrollbar;
151 let positionRatio;
152 positionRatio = (getPointerPosition(e) - $el.offset()[swiper.isHorizontal() ? 'left' : 'top'] - (dragStartPos !== null ? dragStartPos : dragSize / 2)) / (trackSize - dragSize);
153 positionRatio = Math.max(Math.min(positionRatio, 1), 0);
154
155 if (rtl) {
156 positionRatio = 1 - positionRatio;
157 }
158
159 const position = swiper.minTranslate() + (swiper.maxTranslate() - swiper.minTranslate()) * positionRatio;
160 swiper.updateProgress(position);
161 swiper.setTranslate(position);
162 swiper.updateActiveIndex();
163 swiper.updateSlidesClasses();
164 }
165
166 function onDragStart(e) {
167 const params = swiper.params.scrollbar;
168 const {
169 scrollbar,
170 $wrapperEl
171 } = swiper;
172 const {
173 $el,
174 $dragEl
175 } = scrollbar;
176 isTouched = true;
177 dragStartPos = e.target === $dragEl[0] || e.target === $dragEl ? getPointerPosition(e) - e.target.getBoundingClientRect()[swiper.isHorizontal() ? 'left' : 'top'] : null;
178 e.preventDefault();
179 e.stopPropagation();
180 $wrapperEl.transition(100);
181 $dragEl.transition(100);
182 setDragPosition(e);
183 clearTimeout(dragTimeout);
184 $el.transition(0);
185
186 if (params.hide) {
187 $el.css('opacity', 1);
188 }
189
190 if (swiper.params.cssMode) {
191 swiper.$wrapperEl.css('scroll-snap-type', 'none');
192 }
193
194 emit('scrollbarDragStart', e);
195 }
196
197 function onDragMove(e) {
198 const {
199 scrollbar,
200 $wrapperEl
201 } = swiper;
202 const {
203 $el,
204 $dragEl
205 } = scrollbar;
206 if (!isTouched) return;
207 if (e.preventDefault) e.preventDefault();else e.returnValue = false;
208 setDragPosition(e);
209 $wrapperEl.transition(0);
210 $el.transition(0);
211 $dragEl.transition(0);
212 emit('scrollbarDragMove', e);
213 }
214
215 function onDragEnd(e) {
216 const params = swiper.params.scrollbar;
217 const {
218 scrollbar,
219 $wrapperEl
220 } = swiper;
221 const {
222 $el
223 } = scrollbar;
224 if (!isTouched) return;
225 isTouched = false;
226
227 if (swiper.params.cssMode) {
228 swiper.$wrapperEl.css('scroll-snap-type', '');
229 $wrapperEl.transition('');
230 }
231
232 if (params.hide) {
233 clearTimeout(dragTimeout);
234 dragTimeout = nextTick(() => {
235 $el.css('opacity', 0);
236 $el.transition(400);
237 }, 1000);
238 }
239
240 emit('scrollbarDragEnd', e);
241
242 if (params.snapOnRelease) {
243 swiper.slideToClosest();
244 }
245 }
246
247 function events(method) {
248 const {
249 scrollbar,
250 touchEventsTouch,
251 touchEventsDesktop,
252 params,
253 support
254 } = swiper;
255 const $el = scrollbar.$el;
256 if (!$el) return;
257 const target = $el[0];
258 const activeListener = support.passiveListener && params.passiveListeners ? {
259 passive: false,
260 capture: false
261 } : false;
262 const passiveListener = support.passiveListener && params.passiveListeners ? {
263 passive: true,
264 capture: false
265 } : false;
266 if (!target) return;
267 const eventMethod = method === 'on' ? 'addEventListener' : 'removeEventListener';
268
269 if (!support.touch) {
270 target[eventMethod](touchEventsDesktop.start, onDragStart, activeListener);
271 document[eventMethod](touchEventsDesktop.move, onDragMove, activeListener);
272 document[eventMethod](touchEventsDesktop.end, onDragEnd, passiveListener);
273 } else {
274 target[eventMethod](touchEventsTouch.start, onDragStart, activeListener);
275 target[eventMethod](touchEventsTouch.move, onDragMove, activeListener);
276 target[eventMethod](touchEventsTouch.end, onDragEnd, passiveListener);
277 }
278 }
279
280 function enableDraggable() {
281 if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;
282 events('on');
283 }
284
285 function disableDraggable() {
286 if (!swiper.params.scrollbar.el || !swiper.scrollbar.el) return;
287 events('off');
288 }
289
290 function init() {
291 const {
292 scrollbar,
293 $el: $swiperEl
294 } = swiper;
295 swiper.params.scrollbar = createElementIfNotDefined(swiper, swiper.originalParams.scrollbar, swiper.params.scrollbar, {
296 el: 'swiper-scrollbar'
297 });
298 const params = swiper.params.scrollbar;
299 if (!params.el) return;
300 let $el = $(params.el);
301
302 if (swiper.params.uniqueNavElements && typeof params.el === 'string' && $el.length > 1 && $swiperEl.find(params.el).length === 1) {
303 $el = $swiperEl.find(params.el);
304 }
305
306 $el.addClass(swiper.isHorizontal() ? params.horizontalClass : params.verticalClass);
307 let $dragEl = $el.find(`.${swiper.params.scrollbar.dragClass}`);
308
309 if ($dragEl.length === 0) {
310 $dragEl = $(`<div class="${swiper.params.scrollbar.dragClass}"></div>`);
311 $el.append($dragEl);
312 }
313
314 Object.assign(scrollbar, {
315 $el,
316 el: $el[0],
317 $dragEl,
318 dragEl: $dragEl[0]
319 });
320
321 if (params.draggable) {
322 enableDraggable();
323 }
324
325 if ($el) {
326 $el[swiper.enabled ? 'removeClass' : 'addClass'](swiper.params.scrollbar.lockClass);
327 }
328 }
329
330 function destroy() {
331 const params = swiper.params.scrollbar;
332 const $el = swiper.scrollbar.$el;
333
334 if ($el) {
335 $el.removeClass(swiper.isHorizontal() ? params.horizontalClass : params.verticalClass);
336 }
337
338 disableDraggable();
339 }
340
341 on('init', () => {
342 if (swiper.params.scrollbar.enabled === false) {
343 // eslint-disable-next-line
344 disable();
345 } else {
346 init();
347 updateSize();
348 setTranslate();
349 }
350 });
351 on('update resize observerUpdate lock unlock', () => {
352 updateSize();
353 });
354 on('setTranslate', () => {
355 setTranslate();
356 });
357 on('setTransition', (_s, duration) => {
358 setTransition(duration);
359 });
360 on('enable disable', () => {
361 const {
362 $el
363 } = swiper.scrollbar;
364
365 if ($el) {
366 $el[swiper.enabled ? 'removeClass' : 'addClass'](swiper.params.scrollbar.lockClass);
367 }
368 });
369 on('destroy', () => {
370 destroy();
371 });
372
373 const enable = () => {
374 swiper.$el.removeClass(swiper.params.scrollbar.scrollbarDisabledClass);
375
376 if (swiper.scrollbar.$el) {
377 swiper.scrollbar.$el.removeClass(swiper.params.scrollbar.scrollbarDisabledClass);
378 }
379
380 init();
381 updateSize();
382 setTranslate();
383 };
384
385 const disable = () => {
386 swiper.$el.addClass(swiper.params.scrollbar.scrollbarDisabledClass);
387
388 if (swiper.scrollbar.$el) {
389 swiper.scrollbar.$el.addClass(swiper.params.scrollbar.scrollbarDisabledClass);
390 }
391
392 destroy();
393 };
394
395 Object.assign(swiper.scrollbar, {
396 enable,
397 disable,
398 updateSize,
399 setTranslate,
400 init,
401 destroy
402 });
403}
\No newline at end of file