/**
|
* @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
|
)
|
)
|
)
|
}
|
}
|
}
|
}
|
}
|