UNPKG

@zebra-ui/swiper

Version:

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

773 lines (752 loc) 16.5 kB
import { h, ref, onMounted, onUpdated, onBeforeUnmount, watch, nextTick, provide } from 'vue' import SwiperCore from '../swiper' import { getParams } from '../components-shared/get-params' import { mountSwiper } from '../components-shared/mount-swiper' import { needsScrollbar, needsNavigation, needsPagination, uniqueClasses, extend, wrapperClass } from '../components-shared/utils' import { getChangedParams } from '../components-shared/get-changed-params' import { getChildren } from './get-children' import { updateSwiper } from '../components-shared/update-swiper' import { renderVirtual } from './virtual' import { updateOnVirtualData } from '../components-shared/update-on-virtual-data' const ZSwiperNative = { name: 'Swiper', props: { tag: { type: String, default: 'div' }, wrapperTag: { type: String, default: 'div' }, modules: { type: Array, default: undefined }, init: { type: Boolean, default: undefined }, direction: { type: String, default: undefined }, oneWayMovement: { type: Boolean, default: undefined }, swiperElementNodeName: { type: String, default: 'SWIPER-CONTAINER' }, touchEventsTarget: { type: String, default: undefined }, initialSlide: { type: Number, default: undefined }, speed: { type: Number, default: undefined }, cssMode: { type: Boolean, default: undefined }, updateOnWindowResize: { type: Boolean, default: undefined }, resizeObserver: { type: Boolean, default: undefined }, nested: { type: Boolean, default: undefined }, focusableElements: { type: String, default: undefined }, width: { type: Number, default: undefined }, height: { type: Number, default: undefined }, preventInteractionOnTransition: { type: Boolean, default: undefined }, userAgent: { type: String, default: undefined }, url: { type: String, default: undefined }, edgeSwipeDetection: { type: [Boolean, String], default: undefined }, edgeSwipeThreshold: { type: Number, default: undefined }, autoHeight: { type: Boolean, default: undefined }, setWrapperSize: { type: Boolean, default: undefined }, virtualTranslate: { type: Boolean, default: undefined }, effect: { type: String, default: undefined }, breakpoints: { type: Object, default: undefined }, breakpointsBase: { type: String, default: undefined }, spaceBetween: { type: [Number, String], default: undefined }, slidesPerView: { type: [Number, String], default: undefined }, maxBackfaceHiddenSlides: { type: Number, default: undefined }, slidesPerGroup: { type: Number, default: undefined }, slidesPerGroupSkip: { type: Number, default: undefined }, slidesPerGroupAuto: { type: Boolean, default: undefined }, centeredSlides: { type: Boolean, default: undefined }, centeredSlidesBounds: { type: Boolean, default: undefined }, slidesOffsetBefore: { type: Number, default: undefined }, slidesOffsetAfter: { type: Number, default: undefined }, normalizeSlideIndex: { type: Boolean, default: undefined }, centerInsufficientSlides: { type: Boolean, default: undefined }, watchOverflow: { type: Boolean, default: undefined }, roundLengths: { type: Boolean, default: undefined }, touchRatio: { type: Number, default: undefined }, touchAngle: { type: Number, default: undefined }, simulateTouch: { type: Boolean, default: undefined }, shortSwipes: { type: Boolean, default: undefined }, longSwipes: { type: Boolean, default: undefined }, longSwipesRatio: { type: Number, default: undefined }, longSwipesMs: { type: Number, default: undefined }, followFinger: { type: Boolean, default: undefined }, allowTouchMove: { type: Boolean, default: undefined }, threshold: { type: Number, default: undefined }, touchMoveStopPropagation: { type: Boolean, default: undefined }, touchStartPreventDefault: { type: Boolean, default: undefined }, touchStartForcePreventDefault: { type: Boolean, default: undefined }, touchReleaseOnEdges: { type: Boolean, default: undefined }, uniqueNavElements: { type: Boolean, default: undefined }, resistance: { type: Boolean, default: undefined }, resistanceRatio: { type: Number, default: undefined }, watchSlidesProgress: { type: Boolean, default: undefined }, grabCursor: { type: Boolean, default: undefined }, preventClicks: { type: Boolean, default: undefined }, preventClicksPropagation: { type: Boolean, default: undefined }, slideToClickedSlide: { type: Boolean, default: undefined }, loop: { type: Boolean, default: undefined }, loopedSlides: { type: Number, default: undefined }, loopPreventsSliding: { type: Boolean, default: undefined }, rewind: { type: Boolean, default: undefined }, allowSlidePrev: { type: Boolean, default: undefined }, allowSlideNext: { type: Boolean, default: undefined }, swipeHandler: { type: Boolean, default: undefined }, noSwiping: { type: Boolean, default: undefined }, noSwipingClass: { type: String, default: undefined }, noSwipingSelector: { type: String, default: undefined }, passiveListeners: { type: Boolean, default: undefined }, containerModifierClass: { type: String, default: undefined }, slideClass: { type: String, default: undefined }, slideActiveClass: { type: String, default: undefined }, slideVisibleClass: { type: String, default: undefined }, slideFullyVisibleClass: { type: String, default: undefined }, slideBlankClass: { type: String, default: undefined }, slideNextClass: { type: String, default: undefined }, slidePrevClass: { type: String, default: undefined }, wrapperClass: { type: String, default: undefined }, lazyPreloaderClass: { type: String, default: undefined }, lazyPreloadPrevNext: { type: Number, default: undefined }, runCallbacksOnInit: { type: Boolean, default: undefined }, observer: { type: Boolean, default: undefined }, observeParents: { type: Boolean, default: undefined }, observeSlideChildren: { type: Boolean, default: undefined }, a11y: { type: [Boolean, Object], default: undefined }, autoplay: { type: [Boolean, Object], default: undefined }, controller: { type: Object, default: undefined }, coverflowEffect: { type: Object, default: undefined }, cubeEffect: { type: Object, default: undefined }, fadeEffect: { type: Object, default: undefined }, flipEffect: { type: Object, default: undefined }, creativeEffect: { type: Object, default: undefined }, cardsEffect: { type: Object, default: undefined }, customEffect: { type: Object, default: undefined }, hashNavigation: { type: [Boolean, Object], default: undefined }, history: { type: [Boolean, Object], default: undefined }, keyboard: { type: [Boolean, Object], default: undefined }, mousewheel: { type: [Boolean, Object], default: undefined }, navigation: { type: [Boolean, Object], default: undefined }, pagination: { type: [Boolean, Object], default: undefined }, parallax: { type: [Boolean, Object], default: undefined }, scrollbar: { type: [Boolean, Object], default: undefined }, thumbs: { type: Object, default: undefined }, virtual: { type: [Boolean, Object], default: undefined }, zoom: { type: [Boolean, Object], default: undefined }, grid: { type: [Object], default: undefined }, freeMode: { type: [Boolean, Object], default: undefined }, enabled: { type: Boolean, default: undefined } }, emits: [ '_beforeBreakpoint', '_containerClasses', '_slideClass', '_slideClasses', '_swiper', '_freeModeNoMomentumRelease', 'activeIndexChange', 'afterInit', 'autoplay', 'autoplayStart', 'autoplayStop', 'autoplayPause', 'autoplayResume', 'autoplayTimeLeft', 'beforeDestroy', 'beforeInit', 'beforeLoopFix', 'beforeResize', 'beforeSlideChangeStart', 'beforeTransitionStart', 'breakpoint', 'changeDirection', 'click', 'disable', 'doubleTap', 'doubleClick', 'destroy', 'enable', 'fromEdge', 'hashChange', 'hashSet', 'init', 'keyPress', 'lock', 'loopFix', 'momentumBounce', 'navigationHide', 'navigationShow', 'navigationPrev', 'navigationNext', 'observerUpdate', 'orientationchange', 'paginationHide', 'paginationRender', 'paginationShow', 'paginationUpdate', 'progress', 'reachBeginning', 'reachEnd', 'realIndexChange', 'resize', 'scroll', 'scrollbarDragEnd', 'scrollbarDragMove', 'scrollbarDragStart', 'setTransition', 'setTranslate', 'slidesUpdated', 'slideChange', 'slideChangeTransitionEnd', 'slideChangeTransitionStart', 'slideNextTransitionEnd', 'slideNextTransitionStart', 'slidePrevTransitionEnd', 'slidePrevTransitionStart', 'slideResetTransitionStart', 'slideResetTransitionEnd', 'sliderMove', 'sliderFirstMove', 'slidesLengthChange', 'slidesGridLengthChange', 'snapGridLengthChange', 'snapIndexChange', 'swiper', 'tap', 'toEdge', 'touchEnd', 'touchMove', 'touchMoveOpposite', 'touchStart', 'transitionEnd', 'transitionStart', 'unlock', 'update', 'virtualUpdate', 'zoomChange' ], setup(props, { slots: originalSlots, emit }) { const { tag: Tag, wrapperTag: WrapperTag } = props const containerClasses = ref('swiper') const virtualData = ref(null) const breakpointChanged = ref(false) const initializedRef = ref(false) const swiperElRef = ref(null) const swiperRef = ref(null) const oldPassedParamsRef = ref(null) const slidesRef = { value: [] } const oldSlidesRef = { value: [] } const nextElRef = ref(null) const prevElRef = ref(null) const paginationElRef = ref(null) const scrollbarElRef = ref(null) const { params: swiperParams, passedParams } = getParams(props, false) getChildren(originalSlots, slidesRef, oldSlidesRef) oldPassedParamsRef.value = passedParams oldSlidesRef.value = slidesRef.value const onBeforeBreakpoint = () => { getChildren(originalSlots, slidesRef, oldSlidesRef) breakpointChanged.value = true } swiperParams.onAny = (event, ...args) => { emit(event, ...args) } Object.assign(swiperParams.on, { _beforeBreakpoint: onBeforeBreakpoint, _containerClasses(swiper, classes) { containerClasses.value = classes } }) // init Swiper const passParams = { ...swiperParams } delete passParams.wrapperClass swiperRef.value = new SwiperCore(passParams) if (swiperRef.value.virtual && swiperRef.value.params.virtual.enabled) { swiperRef.value.virtual.slides = slidesRef.value const extendWith = { cache: false, slides: slidesRef.value, renderExternal: (data) => { virtualData.value = data }, renderExternalUpdate: false } extend(swiperRef.value.params.virtual, extendWith) extend(swiperRef.value.originalParams.virtual, extendWith) } onUpdated(() => { // set initialized flag if (!initializedRef.value && swiperRef.value) { swiperRef.value.emitSlidesClasses() initializedRef.value = true } // watch for params change const { passedParams: newPassedParams } = getParams(props, false) const changedParams = getChangedParams( newPassedParams, oldPassedParamsRef.value, slidesRef.value, oldSlidesRef.value, (c) => c.props && c.props.key ) oldPassedParamsRef.value = newPassedParams if ( (changedParams.length || breakpointChanged.value) && swiperRef.value && !swiperRef.value.destroyed ) { updateSwiper({ swiper: swiperRef.value, slides: slidesRef.value, passedParams: newPassedParams, changedParams, nextEl: nextElRef.value, prevEl: prevElRef.value, scrollbarEl: scrollbarElRef.value, paginationEl: paginationElRef.value, tag: 'native' }) } breakpointChanged.value = false }) provide('swiper', swiperRef) // update on virtual update watch(virtualData, () => { nextTick(() => { updateOnVirtualData(swiperRef.value) }) }) // mount swiper onMounted(() => { if (!swiperElRef.value) return mountSwiper( { el: swiperElRef.value, nextEl: nextElRef.value, prevEl: prevElRef.value, paginationEl: paginationElRef.value, scrollbarEl: scrollbarElRef.value, swiper: swiperRef.value }, swiperParams ) emit('swiper', swiperRef.value) }) onBeforeUnmount(() => { if (swiperRef.value && !swiperRef.value.destroyed) { swiperRef.value.destroy(true, false) } }) // bypass swiper instance to slides function renderSlides(slides) { if (swiperParams.virtual) { return renderVirtual(swiperRef, slides, virtualData.value) } slides.forEach((slide, index) => { if (!slide.props) slide.props = {} slide.props.swiperRef = swiperRef slide.props.swiperSlideIndex = index }) return slides } return () => { const { slides, slots } = getChildren( originalSlots, slidesRef, oldSlidesRef ) return h( Tag, { ref: swiperElRef, class: uniqueClasses(containerClasses.value) }, [ slots['container-start'], h( WrapperTag, { class: wrapperClass(swiperParams.wrapperClass) }, [slots['wrapper-start'], renderSlides(slides), slots['wrapper-end']] ), needsNavigation(props) && [ h('div', { ref: prevElRef, class: 'swiper-button-prev' }), h('div', { ref: nextElRef, class: 'swiper-button-next' }) ], needsScrollbar(props) && h('div', { ref: scrollbarElRef, class: 'swiper-scrollbar' }), needsPagination(props) && h('div', { ref: paginationElRef, class: 'swiper-pagination' }), slots['container-end'] ] ) } } } export { ZSwiperNative }