UNPKG

@zebra-ui/swiper

Version:

专为多端设计的高性能swiper轮播组件库,支持多种复杂的 3D swiper轮播效果。

323 lines (296 loc) 9.78 kB
import { isWeb, showWarning, simulateRequestAnimationFrame } from '../../shared/utils' import type { LoopFix, LoopFixOptions } from '../../../types/components/core/loop/loop-fix' import type { SwiperInterface } from '../../../types/swiper-class' const loopFix: LoopFix = function ( this: SwiperInterface, { slideRealIndex, slideTo = true, direction, setTranslate, activeSlideIndex, byController, byMousewheel }: LoopFixOptions = {} ) { const swiper = this as SwiperInterface & { __preventObserver__?: boolean } if (!swiper.params.loop) return swiper.emit('beforeLoopFix') const { slides, allowSlidePrev, allowSlideNext, slidesEl, params } = swiper const { centeredSlides } = params swiper.allowSlidePrev = true swiper.allowSlideNext = true if ( swiper.virtual && typeof swiper.params.virtual === 'object' && swiper.params.virtual.enabled ) { if (slideTo) { if (!params.centeredSlides && swiper.snapIndex === 0) { swiper.slideTo(swiper.virtual.slides.length, 0, false, true) } else if ( params.centeredSlides && swiper.snapIndex < Number(params.slidesPerView) ) { swiper.slideTo( swiper.virtual.slides.length + swiper.snapIndex, 0, false, true ) } else if (swiper.snapIndex === swiper.snapGrid.length - 1) { swiper.slideTo(swiper.virtual.slidesBefore, 0, false, true) } } swiper.allowSlidePrev = allowSlidePrev swiper.allowSlideNext = allowSlideNext swiper.emit('loopFix') return } let { slidesPerView } = params if (slidesPerView === 'auto') { slidesPerView = swiper.slidesPerViewDynamic() } else { slidesPerView = Math.ceil(parseFloat(String(params.slidesPerView))) if (centeredSlides && slidesPerView % 2 === 0) { slidesPerView = slidesPerView + 1 } } const slidesPerGroup = params.slidesPerGroupAuto ? slidesPerView : params.slidesPerGroup || 1 let loopedSlides = slidesPerGroup if (loopedSlides % slidesPerGroup !== 0) { loopedSlides += slidesPerGroup - (loopedSlides % slidesPerGroup) } loopedSlides += params.loopAdditionalSlides || 0 swiper.loopedSlides = loopedSlides const gridEnabled = swiper.grid && params.grid && params.grid.rows && params.grid.rows > 1 if (slides.length < slidesPerView + loopedSlides) { showWarning( 'Swiper Loop Warning: The number of slides is not enough for loop mode, it will be disabled and not function properly. You need to add more slides (or make duplicates) or lower the values of slidesPerView and slidesPerGroup parameters' ) } else if (gridEnabled && params.grid?.fill === 'row') { showWarning( 'Swiper Loop Warning: Loop mode is not compatible with grid.fill = `row`' ) } const prependSlidesIndexes: number[] = [] const appendSlidesIndexes: number[] = [] let { activeIndex } = swiper if (typeof activeSlideIndex === 'undefined') { activeSlideIndex = swiper.getSlideIndex( slides.filter((el) => el.classList.contains(params.slideActiveClass || '') )[0] as HTMLElement ) } else { activeIndex = activeSlideIndex } const isNext = direction === 'next' || !direction const isPrev = direction === 'prev' || !direction let slidesPrepended = 0 let slidesAppended = 0 const cols = gridEnabled ? Math.ceil(slides.length / (params.grid?.rows || 1)) : slides.length const activeColIndex = gridEnabled ? (slides[activeSlideIndex || 0] as any).column : activeSlideIndex const activeColIndexWithShift = activeColIndex + (centeredSlides && typeof setTranslate === 'undefined' ? -slidesPerView / 2 + 0.5 : 0) // prepend last slides before start if (activeColIndexWithShift < loopedSlides) { slidesPrepended = Math.max( loopedSlides - activeColIndexWithShift, slidesPerGroup ) for (let i = 0; i < loopedSlides - activeColIndexWithShift; i += 1) { const index = i - Math.floor(i / cols) * cols if (gridEnabled) { const colIndexToPrepend = cols - index - 1 for (let i = slides.length - 1; i >= 0; i -= 1) { if ((slides[i] as any).column === colIndexToPrepend) prependSlidesIndexes.push(i) } } else { prependSlidesIndexes.push(cols - index - 1) } } } else if (activeColIndexWithShift + slidesPerView > cols - loopedSlides) { slidesAppended = Math.max( activeColIndexWithShift - (cols - loopedSlides * 2), slidesPerGroup ) for (let i = 0; i < slidesAppended; i += 1) { const index = i - Math.floor(i / cols) * cols if (gridEnabled) { slides.forEach((slide, slideIndex) => { if ((slide as any).column === index) appendSlidesIndexes.push(slideIndex) }) } else { appendSlidesIndexes.push(index) } } } swiper.__preventObserver__ = true if (isWeb()) { requestAnimationFrame(() => { swiper.__preventObserver__ = false }) } else { simulateRequestAnimationFrame(() => { swiper.__preventObserver__ = false }) } if (isPrev) { if (isWeb()) { prependSlidesIndexes.forEach((index) => { ;(slides[index] as any).swiperLoopMoveDOM = true slidesEl.prepend(slides[index] as HTMLElement) ;(slides[index] as any).swiperLoopMoveDOM = false }) } else { // @ts-ignore prependSlidesIndexes.length && slidesEl.prepend(prependSlidesIndexes) } } if (isNext) { if (isWeb()) { appendSlidesIndexes.forEach((index) => { ;(slides[index] as any).swiperLoopMoveDOM = true slidesEl.append(slides[index] as HTMLElement) ;(slides[index] as any).swiperLoopMoveDOM = false }) } else { // @ts-ignore appendSlidesIndexes.length && slidesEl.append(appendSlidesIndexes) } } swiper.recalcSlides() if (params.slidesPerView === 'auto') { swiper.updateSlides() } else if ( gridEnabled && ((prependSlidesIndexes.length > 0 && isPrev) || (appendSlidesIndexes.length > 0 && isNext)) ) { swiper.slides.forEach((slide, slideIndex) => { swiper.grid.updateSlide( slideIndex, slide as HTMLElement, swiper.slides as HTMLElement[] ) }) } if (params.watchSlidesProgress) { swiper.updateSlidesOffset() } if (slideTo) { if (prependSlidesIndexes.length > 0 && isPrev) { if (typeof slideRealIndex === 'undefined') { const currentSlideTranslate = swiper.slidesGrid[activeIndex] const newSlideTranslate = swiper.slidesGrid[activeIndex + slidesPrepended] const diff = newSlideTranslate - currentSlideTranslate if (byMousewheel) { swiper.setTranslate(swiper.translate - diff) } else { swiper.slideTo( activeIndex + Math.ceil(slidesPrepended), 0, false, true ) if (setTranslate) { swiper.touchEventsData.startTranslate = swiper.touchEventsData.startTranslate - diff swiper.touchEventsData.currentTranslate = swiper.touchEventsData.currentTranslate - diff } } } else { if (setTranslate) { const shift = gridEnabled ? prependSlidesIndexes.length / (params.grid?.rows || 1) : prependSlidesIndexes.length swiper.slideTo(swiper.activeIndex + shift, 0, false, true) swiper.touchEventsData.currentTranslate = swiper.translate } } } else if (appendSlidesIndexes.length > 0 && isNext) { if (typeof slideRealIndex === 'undefined') { const currentSlideTranslate = swiper.slidesGrid[activeIndex] const newSlideTranslate = swiper.slidesGrid[activeIndex - slidesAppended] const diff = newSlideTranslate - currentSlideTranslate if (byMousewheel) { swiper.setTranslate(swiper.translate - diff) } else { swiper.slideTo(activeIndex - slidesAppended, 0, false, true) if (setTranslate) { swiper.touchEventsData.startTranslate = swiper.touchEventsData.startTranslate - diff swiper.touchEventsData.currentTranslate = swiper.touchEventsData.currentTranslate - diff } } } else { const shift = gridEnabled ? appendSlidesIndexes.length / (params.grid?.rows || 1) : appendSlidesIndexes.length swiper.slideTo(swiper.activeIndex - shift, 0, false, true) } } } swiper.allowSlidePrev = allowSlidePrev swiper.allowSlideNext = allowSlideNext if (swiper.controller && swiper.controller.control && !byController) { const loopParams = { slideRealIndex, direction, setTranslate, activeSlideIndex, byController: true } if (Array.isArray(swiper.controller.control)) { swiper.controller.control.forEach((c) => { if (!c.destroyed && c.params.loop) c.loopFix({ ...loopParams, slideTo: c.params.slidesPerView === params.slidesPerView ? slideTo : false }) }) } else if ( swiper.controller.control instanceof swiper.constructor && // @ts-ignore swiper.controller.control.params.loop ) { // @ts-ignore swiper.controller.control.loopFix({ ...loopParams, slideTo: // @ts-ignore swiper.controller.control.params.slidesPerView === params.slidesPerView ? slideTo : false }) } } swiper.emit('loopFix') } export default loopFix