保誠-保戶業務員媒合平台
HelenHuang
2022-06-09 9bdb95c9e34cef640534e5e5a1e2225a80442000
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/**
 * @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
              )
            )
          )
        }
      }
    }
  }
}