vue-awesome-swiper
Version:
Swiper component for Vue
146 lines (133 loc) • 4.91 kB
text/typescript
/**
* @file vue-awesome-swiper
* @module directive
* @author Surmon <https://github.com/surmon-china>
*/
import { DirectiveOptions, VNode } from 'vue'
import { DirectiveBinding } from 'vue/types/options'
import Swiper, { SwiperOptions } from 'swiper'
import { DEFAULT_CLASSES, CoreNames, ComponentEvents, ComponentPropNames } from './constants'
import { handleClickSlideEvent, bindSwiperEvents } from './event'
import { kebabcase } from './utils'
const INSTANCE_NAME_KEY = 'instanceName'
export default function getDirective(SwiperClass: typeof Swiper, globalOptions?: SwiperOptions): DirectiveOptions {
const getStandardisedOptionByAttrs = (vnode: VNode, key: string): any => {
const value = vnode.data?.attrs?.[key]
return value !== undefined
? value
: vnode.data?.attrs?.[kebabcase(key)]
}
// Get swiper instace name in directive
const getSwiperInstanceName = (element: HTMLElement, binding: DirectiveBinding, vnode: VNode): string => {
return (
binding.arg ||
getStandardisedOptionByAttrs(vnode, INSTANCE_NAME_KEY) ||
element.id ||
CoreNames.SwiperInstance
)
}
const getSwiperInstance = (element: HTMLElement, binding: DirectiveBinding, vnode: VNode): Swiper | null => {
const instanceName = getSwiperInstanceName(element, binding, vnode)
return (vnode.context as any)[instanceName] || null
}
const getSwipeOptions = (binding: DirectiveBinding): SwiperOptions => {
return binding.value || globalOptions
}
const getBooleanValueByInput = (input: any): boolean => {
return [true, undefined, null, ''].includes(input)
}
// Emit event in Vue directive
const getEventEmiter = (vnode: VNode) => {
const handlers = vnode.data?.on || vnode.componentOptions?.listeners
return (name: string, ...args: any[]) => {
const handle = (handlers as any)?.[name]
if (handle) {
handle.fns(...args)
}
}
}
return {
// Init
bind(element, binding, vnode) {
// auto class name
if (element.className.indexOf(DEFAULT_CLASSES.containerClass) === -1) {
element.className += ((element.className ? ' ' : '') + DEFAULT_CLASSES.containerClass)
}
// bind click event
element.addEventListener('click', event => {
const emitEvent = getEventEmiter(vnode)
const swiper = getSwiperInstance(element, binding, vnode)
handleClickSlideEvent(swiper, event, emitEvent)
})
},
// DOM inserted
inserted(element, binding, vnode) {
const context = vnode.context
const swiperOptions = getSwipeOptions(binding)
const instanceName = getSwiperInstanceName(element, binding, vnode)
const emitEvent = getEventEmiter(vnode)
const vueContext = context as any
let swiper: Swiper = vueContext?.[instanceName]
// Swiper will destroy but not delete instance, when used <keep-alive>
if (!swiper || (swiper as any).destroyed) {
swiper = new SwiperClass(element, swiperOptions)
vueContext[instanceName] = swiper
bindSwiperEvents(swiper, emitEvent)
emitEvent(ComponentEvents.Ready, swiper)
// MARK: Reinstance when the nexttick with <keep-alive>
// Vue.nextTick(instancing) | setTimeout(instancing)
}
},
// On options changed or DOM updated
componentUpdated(element, binding, vnode) {
const autoUpdate = getStandardisedOptionByAttrs(
vnode,
ComponentPropNames.AutoUpdate
)
if (getBooleanValueByInput(autoUpdate)) {
const swiper = getSwiperInstance(element, binding, vnode)
if (swiper) {
const swiperOptions = getSwipeOptions(binding)
const isLoop = swiperOptions.loop
if (isLoop) {
;(swiper as any)?.loopDestroy?.()
}
swiper?.update?.()
swiper.navigation?.update?.()
swiper.pagination?.render?.()
swiper.pagination?.update?.()
if (isLoop) {
;(swiper as any)?.loopCreate?.()
swiper?.update?.()
}
}
}
},
// Destroy this directive
unbind(element, binding, vnode) {
const autoDestroy = getStandardisedOptionByAttrs(
vnode,
ComponentPropNames.AutoDestroy
)
if (getBooleanValueByInput(autoDestroy)) {
const swiper = getSwiperInstance(element, binding, vnode)
if (swiper && (swiper as any).initialized) {
swiper?.destroy?.(
getBooleanValueByInput(
getStandardisedOptionByAttrs(
vnode,
ComponentPropNames.DeleteInstanceOnDestroy
)
),
getBooleanValueByInput(
getStandardisedOptionByAttrs(
vnode,
ComponentPropNames.CleanupStylesOnDestroy
)
)
)
}
}
}
}
}