swiper
Version:
Most modern mobile touch slider and framework with hardware accelerated transitions
351 lines (349 loc) • 11.3 kB
JavaScript
const Autoplay = ({ swiper, extendParams, on, emit, params }) => {
swiper.autoplay = {
running: false,
paused: false,
timeLeft: 0,
};
extendParams({
autoplay: {
enabled: false,
delay: 3000,
waitForTransition: true,
disableOnInteraction: false,
stopOnLastSlide: false,
reverseDirection: false,
pauseOnMouseEnter: false,
},
});
function getParams() {
return swiper.params.autoplay;
}
// params here is the user-supplied passedParams; extendParams hasn't yet
// merged the defaults into swiper.params.autoplay at this point.
const initialAutoplayDelay = typeof params.autoplay === 'object' &&
params.autoplay &&
typeof params.autoplay.delay === 'number'
? params.autoplay.delay
: 3000;
let timeout;
let raf;
let autoplayDelayTotal = initialAutoplayDelay;
let autoplayDelayCurrent = initialAutoplayDelay;
let autoplayTimeLeft = 0;
let autoplayStartTime = new Date().getTime();
let wasPaused = false;
let isTouched = false;
let pausedByTouch = false;
let touchStartTimeout;
let pausedByInteraction = false;
let pausedByPointerEnter = false;
function onTransitionEnd(e) {
if (!swiper || swiper.destroyed || !swiper.wrapperEl)
return;
if (e.target !== swiper.wrapperEl)
return;
swiper.wrapperEl.removeEventListener('transitionend', onTransitionEnd);
const detail = e.detail;
if (pausedByPointerEnter || (detail && detail.bySwiperTouchMove)) {
return;
}
resume();
}
const calcTimeLeft = () => {
if (swiper.destroyed || !swiper.autoplay.running)
return;
if (swiper.autoplay.paused) {
wasPaused = true;
}
else if (wasPaused) {
autoplayDelayCurrent = autoplayTimeLeft;
wasPaused = false;
}
const timeLeft = swiper.autoplay.paused
? autoplayTimeLeft
: autoplayStartTime + autoplayDelayCurrent - new Date().getTime();
swiper.autoplay.timeLeft = timeLeft;
emit('autoplayTimeLeft', timeLeft, timeLeft / autoplayDelayTotal);
raf = requestAnimationFrame(() => {
calcTimeLeft();
});
};
const getSlideDelay = () => {
let activeSlideEl;
const virtualEnabled = !!swiper.params.virtual?.enabled;
if (swiper.virtual && virtualEnabled) {
activeSlideEl = swiper.slides.find((slideEl) => slideEl.classList.contains('swiper-slide-active'));
}
else {
activeSlideEl = swiper.slides[swiper.activeIndex];
}
if (!activeSlideEl)
return undefined;
const attr = activeSlideEl.getAttribute('data-swiper-autoplay');
if (attr == null)
return undefined;
return parseInt(attr, 10);
};
const getTotalDelay = () => {
let totalDelay = getParams().delay;
const currentSlideDelay = getSlideDelay();
if (typeof currentSlideDelay === 'number' &&
!Number.isNaN(currentSlideDelay) &&
currentSlideDelay > 0) {
totalDelay = currentSlideDelay;
}
return totalDelay;
};
const run = (delayForce) => {
if (swiper.destroyed || !swiper.autoplay.running)
return 0;
if (raf !== undefined)
cancelAnimationFrame(raf);
calcTimeLeft();
let delay = delayForce;
if (typeof delay === 'undefined') {
delay = getTotalDelay();
autoplayDelayTotal = delay;
autoplayDelayCurrent = delay;
}
autoplayTimeLeft = delay;
const speed = swiper.params.speed;
const proceed = () => {
if (!swiper || swiper.destroyed)
return;
const autoplayParams = getParams();
if (autoplayParams.reverseDirection) {
if (!swiper.isBeginning || swiper.params.loop || swiper.params.rewind) {
swiper.slidePrev(speed, true, true);
emit('autoplay');
}
else if (!autoplayParams.stopOnLastSlide) {
swiper.slideTo(swiper.slides.length - 1, speed, true, true);
emit('autoplay');
}
}
else {
if (!swiper.isEnd || swiper.params.loop || swiper.params.rewind) {
swiper.slideNext(speed, true, true);
emit('autoplay');
}
else if (!autoplayParams.stopOnLastSlide) {
swiper.slideTo(0, speed, true, true);
emit('autoplay');
}
}
if (swiper.params.cssMode) {
autoplayStartTime = new Date().getTime();
requestAnimationFrame(() => {
run();
});
}
};
if (delay > 0) {
if (timeout !== undefined)
clearTimeout(timeout);
timeout = setTimeout(() => {
proceed();
}, delay);
}
else {
requestAnimationFrame(() => {
proceed();
});
}
return delay;
};
const start = () => {
autoplayStartTime = new Date().getTime();
swiper.autoplay.running = true;
run();
emit('autoplayStart');
return true;
};
const stop = () => {
swiper.autoplay.running = false;
if (timeout !== undefined)
clearTimeout(timeout);
if (raf !== undefined)
cancelAnimationFrame(raf);
emit('autoplayStop');
return true;
};
const pause = (internal, reset) => {
if (swiper.destroyed || !swiper.autoplay.running)
return;
if (timeout !== undefined)
clearTimeout(timeout);
if (!internal) {
pausedByInteraction = true;
}
const proceed = () => {
emit('autoplayPause');
if (getParams().waitForTransition) {
swiper.wrapperEl.addEventListener('transitionend', onTransitionEnd);
}
else {
resume();
}
};
swiper.autoplay.paused = true;
if (reset) {
proceed();
return;
}
const delay = autoplayTimeLeft || getParams().delay;
autoplayTimeLeft = delay - (new Date().getTime() - autoplayStartTime);
if (swiper.isEnd && autoplayTimeLeft < 0 && !swiper.params.loop)
return;
if (autoplayTimeLeft < 0)
autoplayTimeLeft = 0;
proceed();
};
const resume = () => {
if ((swiper.isEnd && autoplayTimeLeft < 0 && !swiper.params.loop) ||
swiper.destroyed ||
!swiper.autoplay.running)
return;
autoplayStartTime = new Date().getTime();
if (pausedByInteraction) {
pausedByInteraction = false;
run(autoplayTimeLeft);
}
else {
run();
}
swiper.autoplay.paused = false;
emit('autoplayResume');
};
const onVisibilityChange = () => {
if (swiper.destroyed || !swiper.autoplay.running)
return;
if (document.visibilityState === 'hidden') {
pausedByInteraction = true;
pause(true);
}
if (document.visibilityState === 'visible') {
resume();
}
};
const onPointerEnter = (e) => {
if (e.pointerType !== 'mouse')
return;
pausedByInteraction = true;
pausedByPointerEnter = true;
if (swiper.animating || swiper.autoplay.paused)
return;
pause(true);
};
const onPointerLeave = (e) => {
if (e.pointerType !== 'mouse')
return;
pausedByPointerEnter = false;
if (swiper.autoplay.paused) {
resume();
}
};
const attachMouseEvents = () => {
if (getParams().pauseOnMouseEnter) {
swiper.el.addEventListener('pointerenter', onPointerEnter);
swiper.el.addEventListener('pointerleave', onPointerLeave);
}
};
const detachMouseEvents = () => {
if (swiper.el && typeof swiper.el !== 'string') {
swiper.el.removeEventListener('pointerenter', onPointerEnter);
swiper.el.removeEventListener('pointerleave', onPointerLeave);
}
};
const attachDocumentEvents = () => {
document.addEventListener('visibilitychange', onVisibilityChange);
};
const detachDocumentEvents = () => {
document.removeEventListener('visibilitychange', onVisibilityChange);
};
on('init', () => {
if (getParams().enabled) {
attachMouseEvents();
attachDocumentEvents();
start();
}
});
on('destroy', () => {
detachMouseEvents();
detachDocumentEvents();
if (swiper.autoplay.running) {
stop();
}
});
on('_freeModeStaticRelease', () => {
if (pausedByTouch || pausedByInteraction) {
resume();
}
});
on('_freeModeNoMomentumRelease', () => {
if (!getParams().disableOnInteraction) {
pause(true, true);
}
else {
stop();
}
});
on('beforeTransitionStart', (_s, _speed, internal) => {
if (swiper.destroyed || !swiper.autoplay.running)
return;
if (internal || !getParams().disableOnInteraction) {
pause(true, true);
}
else {
stop();
}
});
on('sliderFirstMove', () => {
if (swiper.destroyed || !swiper.autoplay.running)
return;
if (getParams().disableOnInteraction) {
stop();
return;
}
isTouched = true;
pausedByTouch = false;
pausedByInteraction = false;
touchStartTimeout = setTimeout(() => {
pausedByInteraction = true;
pausedByTouch = true;
pause(true);
}, 200);
});
on('touchEnd', () => {
if (swiper.destroyed || !swiper.autoplay.running || !isTouched)
return;
if (touchStartTimeout !== undefined)
clearTimeout(touchStartTimeout);
if (timeout !== undefined)
clearTimeout(timeout);
if (getParams().disableOnInteraction) {
pausedByTouch = false;
isTouched = false;
return;
}
if (pausedByTouch && swiper.params.cssMode)
resume();
pausedByTouch = false;
isTouched = false;
});
on('slideChange', () => {
if (swiper.destroyed || !swiper.autoplay.running)
return;
if (swiper.autoplay.paused) {
autoplayTimeLeft = getTotalDelay();
autoplayDelayTotal = getTotalDelay();
}
});
Object.assign(swiper.autoplay, {
start,
stop,
pause,
resume,
});
};
export { Autoplay as default };