UNPKG

@zebra-ui/swiper

Version:

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

328 lines (289 loc) 8.9 kB
import createElementIfNotDefined from '../../components/shared/create-element-if-not-defined' import { isWeb, makeElementsArray } from '../../components/shared/utils' import type { NavigationOptions } from '../../types/modules/navigation' import type { SwiperInterface } from '../../types/swiper-class' import type { PaginationOptions } from '../../types/modules/pagination' export default function Navigation({ swiper, extendParams, on, emit }: { swiper: SwiperInterface extendParams: (params: Record<string, any>) => void on: (event: string, handler: (...args: any[]) => void) => void emit: (event: string, ...args: any[]) => void }): void { extendParams({ navigation: { nextEl: null, prevEl: null, hideOnClick: false, disabledClass: 'swiper-button-disabled', hiddenClass: 'swiper-button-hidden', lockClass: 'swiper-button-lock', navigationDisabledClass: 'swiper-navigation-disabled' } as NavigationOptions }) swiper.navigation = { // @ts-ignore nextEl: null, // @ts-ignore prevEl: null } function getEl( el: string | HTMLElement | null ): HTMLElement | HTMLElement[] | null { let res: HTMLElement | HTMLElement[] | null = null if (el && typeof el === 'string' && swiper.isElement) { res = ((swiper.el as HTMLElement).querySelector(el) as HTMLElement) || ((swiper.hostEl as HTMLElement).querySelector(el) as HTMLElement) if (res) return res } if (el) { if (typeof el === 'string') { res = Array.from(document.querySelectorAll(el)) as HTMLElement[] } if ( swiper.params.uniqueNavElements && typeof el === 'string' && Array.isArray(res) && res.length > 1 && (swiper.el as HTMLElement).querySelectorAll(el).length === 1 ) { res = (swiper.el as HTMLElement).querySelector(el) as HTMLElement } else if (Array.isArray(res) && res.length === 1) { res = res[0] } } return el && !res ? (el as HTMLElement) : (res as HTMLElement) } function toggleEl(el: HTMLElement | HTMLElement[] | null, disabled: boolean) { const params = swiper.params.navigation as NavigationOptions el = makeElementsArray(el) as HTMLElement[] el.forEach((subEl) => { if (subEl) { subEl.classList[disabled ? 'add' : 'remove']( ...(params.disabledClass as string).split(' ') ) if (subEl.tagName === 'BUTTON') { ;(subEl as HTMLButtonElement).disabled = disabled } if (swiper.params.watchOverflow && swiper.enabled) { subEl.classList[swiper.isLocked ? 'add' : 'remove']( params.lockClass as string ) } } }) } function update() { // Update Navigation Buttons const { nextEl, prevEl } = swiper.navigation if (swiper.params.loop) { toggleEl(prevEl, false) toggleEl(nextEl, false) return } toggleEl(prevEl, swiper.isBeginning && !swiper.params.rewind) toggleEl(nextEl, swiper.isEnd && !swiper.params.rewind) } function onPrevClick(e: Event) { e.preventDefault() if (swiper.isBeginning && !swiper.params.loop && !swiper.params.rewind) return swiper.slidePrev() emit('navigationPrev') } function onNextClick(e: Event) { e.preventDefault() if (swiper.isEnd && !swiper.params.loop && !swiper.params.rewind) return swiper.slideNext() emit('navigationNext') } function init() { const params = swiper.params.navigation as NavigationOptions if (isWeb()) { swiper.params.navigation = createElementIfNotDefined( swiper, swiper.originalParams.navigation as Record<string, any>, swiper.params.navigation as Record<string, any>, { nextEl: 'swiper-button-next', prevEl: 'swiper-button-prev' } ) } if (!(params.nextEl || params.prevEl)) return let nextEl = getEl(params.nextEl as string | HTMLElement | null) let prevEl = getEl(params.prevEl as string | HTMLElement | null) Object.assign(swiper.navigation, { nextEl, prevEl }) nextEl = makeElementsArray(nextEl as HTMLElement | HTMLElement[]) prevEl = makeElementsArray(prevEl as HTMLElement | HTMLElement[]) const initButton = (el: HTMLElement, dir: 'next' | 'prev') => { if (el) { if (isWeb()) { el.addEventListener( 'click', dir === 'next' ? onNextClick : onPrevClick ) } else { el.addEventListener( 'click', // @ts-ignore dir === 'next' ? onNextClick.bind(this) : onPrevClick.bind(this), // @ts-ignore 'onClick' ) } } if (!swiper.enabled && el) { el.classList.add(...(params.lockClass as string).split(' ')) } } nextEl.forEach((el) => initButton(el, 'next')) prevEl.forEach((el) => initButton(el, 'prev')) } function destroy() { let { nextEl, prevEl } = swiper.navigation nextEl = makeElementsArray(nextEl) as HTMLElement[] prevEl = makeElementsArray(prevEl) as HTMLElement[] const destroyButton = (el: HTMLElement, dir: 'next' | 'prev') => { if (isWeb()) { el.removeEventListener( 'click', dir === 'next' ? onNextClick : onPrevClick ) } else { el.removeEventListener( 'click', // @ts-ignore dir === 'next' ? onNextClick.bind(this) : onPrevClick.bind(this), // @ts-ignore 'onClick' ) } el.classList.remove( ...( (swiper.params.navigation as NavigationOptions) .disabledClass as string ).split(' ') ) } nextEl.forEach((el) => destroyButton(el, 'next')) prevEl.forEach((el) => destroyButton(el, 'prev')) } on('init', () => { if ((swiper.params.navigation as NavigationOptions).enabled === false) { disable() } else { init() update() } }) on('toEdge fromEdge lock unlock', () => { update() }) on('destroy', () => { destroy() }) on('enable disable', () => { let { nextEl, prevEl } = swiper.navigation nextEl = makeElementsArray(nextEl) prevEl = makeElementsArray(prevEl) if (swiper.enabled) { update() return } ;[...nextEl, ...prevEl] .filter((el) => !!el) .forEach((el) => el.classList.add( (swiper.params.navigation as NavigationOptions).lockClass as string ) ) }) on('click', (_s: any, e: Event & { path?: HTMLElement[] }) => { let { nextEl, prevEl } = swiper.navigation nextEl = makeElementsArray(nextEl) prevEl = makeElementsArray(prevEl) const targetEl = e.target as HTMLElement let targetIsButton = prevEl.includes(targetEl) || nextEl.includes(targetEl) if (swiper.isElement && !targetIsButton) { const path = e.path || (e.composedPath && e.composedPath()) if (path) { targetIsButton = !!path.find( (pathEl) => nextEl.includes(pathEl as HTMLElement) || prevEl.includes(pathEl as HTMLElement) ) } } if ( (swiper.params.navigation as NavigationOptions).hideOnClick && !targetIsButton ) { if ( swiper.pagination && swiper.params.pagination && (swiper.params.pagination as PaginationOptions).clickable && (swiper.pagination.el === targetEl || swiper.pagination.el.contains(targetEl)) ) return let isHidden if (nextEl.length) { isHidden = nextEl[0].classList.contains( (swiper.params.navigation as NavigationOptions).hiddenClass as string ) } else if (prevEl.length) { isHidden = prevEl[0].classList.contains( (swiper.params.navigation as NavigationOptions).hiddenClass as string ) } if (isHidden === true) { emit('navigationShow') } else { emit('navigationHide') } ;[...nextEl, ...prevEl] .filter((el) => !!el) .forEach((el) => el.classList.toggle( (swiper.params.navigation as NavigationOptions) .hiddenClass as string ) ) } }) const enable = () => { swiper.el.classList.remove( ...( (swiper.params.navigation as NavigationOptions) .navigationDisabledClass as string ).split(' ') ) init() update() } const disable = () => { swiper.el.classList.add( ...( (swiper.params.navigation as NavigationOptions) .navigationDisabledClass as string ).split(' ') ) destroy() } Object.assign(swiper.navigation, { enable, disable, update, init, destroy }) }