dengjunjie
5 天以前 4f39dcc195f28fa275fc2d065fbf1bf6a46c21b7
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
<template>
  <!-- #ifdef MP-WEIXIN -->
  <view
    class="tn-c-swiper-item"
    :style="[swiperStyle]"
    :itemData="itemData"
    :currentIndex="currentIndex"
    :containerData="containerData"
    :change:itemData="wxs.itemDataObserver"
    :change:currentIndex="wxs.currentIndexObserver"
    :change:containerData="wxs.containerDataObserver"
    @touchstart="wxs.touchStart"
    :catch:touchmove="touching?wxs.touchMove:''"
    :catch:touchend="touching?wxs.touchEnd:''"
  >
    <view class="item__container tn-c-swiper-item__container" :style="[containerStyle]">
      <slot></slot>
    </view>
  </view>
  <!-- #endif -->
  <!-- #ifndef MP-WEIXIN -->
  <view
    class="tn-c-swiper-item"
    :style="[swiperStyle]"
    :itemData="itemData"
    :currentIndex="currentIndex"
    :containerData="containerData"
    :change:itemData="wxs.itemDataObserver"
    :change:currentIndex="wxs.currentIndexObserver"
    :change:containerData="wxs.containerDataObserver"
    @touchstart="wxs.touchStart"
    @touchmove="wxs.touchMove"
    @touchend="wxs.touchEnd"
  >
    <view class="item__container tn-c-swiper-item__container" :style="[containerStyle]">
      <slot></slot>
    </view>
  </view>
  <!-- #endif -->
</template>
 
<script src="./index.wxs" lang="wxs" module="wxs"></script>
<script>
  export default {
    name: 'tn-custom-swiper-item',
    props: {
      
    },
    computed: {
      // swiperItem公共数据
      itemData() {
        return {
          index: this.index,
          itemWidth: this.itemWidth,
          itemHeight: this.itemHeight,
          itemTop: this.itemTop,
          itemLeft: this.itemLeft
        }
      },
      currentIndex() {
        return this.parentData.currentIndex
      },
      containerData() {
        return {
          duration: this.parentData.duration,
          animationFinish: this.parentData.swiperContainerAnimationFinish,
          circular: this.parentData.circular,
          swiperItemLength: this.swiperItemLength,
          vertical: this.parentData.vertical
        }
      },
      swiperStyle() {
        let style = {}
        style.transform = `translate3d(${this.translateX}%, ${this.translateY}%, 0px)`
        return style
      },
      containerStyle() {
        let style = {}
        if (this.parentData.customSwiperStyle && Object.keys(this.parentData.customSwiperStyle).length > 0) {
          style = this.parentData.customSwiperStyle
        }
        if ((this.currentIndex === 0 && this.index === this.swiperItemLength - 1) || (this.index === this.currentIndex - 1) && 
          (this.parentData.prevSwiperStyle && Object.keys(this.parentData.prevSwiperStyle).length > 0)
        ) {
          // 前一个swiperItem
          const copyStyle = JSON.parse(JSON.stringify(style))
          style = Object.assign(copyStyle, this.parentData.prevSwiperStyle)
        } 
        if ((this.currentIndex === this.swiperItemLength - 1 && this.index === 0) || (this.index === this.currentIndex + 1) &&
          (this.parentData.nextSwiperStyle && Object.keys(this.parentData.nextSwiperStyle).length > 0)
        ) {
          // 后一个swiperItem
          const copyStyle = JSON.parse(JSON.stringify(style))
          style = Object.assign(copyStyle, this.parentData.nextSwiperStyle)
        }
        return style
      }
    },
    data() {
      return {
        // 父组件参数
        parentData: {
          duration: 500,
          currentIndex: 0,
          swiperContainerAnimationFinish: false,
          circular: false,
          vertical: false,
          prevSwiperStyle: {},
          customSwiperStyle: {},
          nextSwiperStyle: {}
        },
        // 标记当前是否正在触摸
        touching: true,
        // 当前swiperItem的偏移位置
        translateX: 0,
        translateY: 0,
        // 当前swiperItem的宽高
        itemWidth: 0,
        itemHeight: 0,
        // 当前swiperItem的位置信息
        itemTop: 0,
        itemLeft: 0,
        // 当前swiperItem的状态 prev current next
        status: 'current',
        // 当前swiperItem的index序号
        index: 0,
        // swiperItem的的数量
        swiperItemLength: 0
      }
    },
    created() {
      this.parent = false
      this.updateParentData()
      // 获取当前父组件children的数量作为当前swiperItem的序号
      this.index = this.parent.children.length
      this.parent && this.parent.children.push(this)
    },
    mounted() {
      this.$nextTick(() => {
        this.initSwiperItem()
      })
    },
    methods: {
      // 初始化swiperItem
      initSwiperItem() {
        this.getSwiperItemRect(() => {
          this.parent.updateAllSwiperItemStyle()
          this.parentData.swiperContainerAnimationFinish = true
        })
      },
      // 获取swiperItem的信息
      async getSwiperItemRect(callback) {
        const swiperItemRes = await this._tGetRect('.tn-c-swiper-item')
        if (!swiperItemRes.height || !swiperItemRes.width) {
          setTimeout(() => {
            this.getSwiperItemRect()
          }, 30)
          return
        }
        
        this.itemWidth = swiperItemRes.width
        this.itemHeight = swiperItemRes.height
        this.itemTop = swiperItemRes.top
        this.itemLeft = swiperItemRes.left
        callback && callback()
      },
      // 更新swiperItem样式
      updateSwiperItemStyle(swiperItemLength, currentIndex = undefined) {
        currentIndex = currentIndex != undefined ? currentIndex : this.parentData.currentIndex
        this.swiperItemLength = swiperItemLength
        // 根据当前swiperItem的序号设置偏移位置
        // 判断当前swiperItem是否为第一个,如果是则将最后的swiperItem移动到当前的前一个位置(即最前面)
        if (currentIndex === 0 && this.index === swiperItemLength - 1) {
          if (this.parentData.vertical) {
            this.translateX = 0
            this.translateY = -100
          } else {
            this.translateX = -100
            this.translateY = 0
          }
        } 
        // 判断当前swiperItem是否为最后一个,如果是则将最前的swiperItem移动到当前的后一个位置(即最后面)
        else if (currentIndex === swiperItemLength - 1 && this.index === 0) {
          if (this.parentData.vertical) {
            this.translateX = 0
            this.translateY = swiperItemLength * 100
          } else {
            this.translateX = swiperItemLength * 100
            this.translateY = 0
          }
        }
        // 正常情况
        else {
          if (this.parentData.vertical) {
            this.translateX = 0
            this.translateY = this.index * 100
          } else {
            this.translateX = this.index * 100
            this.translateY = 0
          }
        }
      },
      // 更新父组件的偏移位置信息
      updateParentSwiperContainerStyle(e) {
        this.parent.updateSwiperContainerStyleWithValue(e.value)
      },
      // 根据方向更新父组件的偏移位置信息
      updateParentSwiperContainerStyleWithDirection(e) {
        this.parent.updateSwiperContainerStyleWithDirection(e.direction)
      },
      // 修改父组件的偏移位置的状态
      changeParentSwiperContainerStyleStatus(e) {
        // reset -> 重置 reload -> 重载
        this.parent.updateSwiperContainerStyleWithDirection(e.status)
      },
      // 更新父组件信息
      updateParentData() {
        this.getParentData('tn-custom-swiper')
      },
      // 更新触摸状态
      updateTouchingStatus(e) {
        this.touching = e.status
        if (e.status) {
          this.parent.stopAutoPlay()
        } else {
          this.parent.startAutoPlay()
        }
      },
      // 提取对应用户自定义样式
      extractCustomStyle(customStyle) {
        let data = {
          transform: {},
          style: {}
        }
        if (!customStyle) return data
        // 允许设置的transform参数
        const allowTransformProps = ['scale','scaleX','scaleY','scaleZ','rotate','rotateX','rotateY','rotateZ']
        for (let prop in customStyle) {
          if (prop.startsWith('transformProp')) {
            // transform里面的样式
            let transformProp = prop.substring('transformProp'.length)
            const index = allowTransformProps.findIndex((item) => {
              return item.toLowerCase() === transformProp.toLowerCase()
            })
            if (index !== -1) {
              transformProp = allowTransformProps[index]
              data.transform[transformProp] = customStyle[prop]
            }
          } else {
            // 普通样式
            data.style[prop] = customStyle[prop]
          }
        }
        return data
      }
    }
  }
</script>
 
<style lang="scss" scoped>
  .tn-c-swiper-item {
    width: 100%;
    height: 100%;
    position: absolute;
    display: block;
    will-change: transform;
    cursor: none;
    transform: translate3d(0px, 0px, 0px);
    
    .item__container {
      width: 100%;
      height: 100%;
      display: block;
      position: absolute;
    }
  }
</style>