@mpxjs/webpack-plugin 2.9.59 → 2.9.64

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/lib/index.js +1 -3
  2. package/lib/platform/style/wx/index.js +344 -270
  3. package/lib/platform/template/wx/component-config/checkbox-group.js +8 -0
  4. package/lib/platform/template/wx/component-config/checkbox.js +8 -0
  5. package/lib/platform/template/wx/component-config/cover-image.js +15 -0
  6. package/lib/platform/template/wx/component-config/cover-view.js +9 -0
  7. package/lib/platform/template/wx/component-config/form.js +13 -1
  8. package/lib/platform/template/wx/component-config/icon.js +8 -0
  9. package/lib/platform/template/wx/component-config/index.js +5 -1
  10. package/lib/platform/template/wx/component-config/label.js +15 -0
  11. package/lib/platform/template/wx/component-config/movable-area.js +18 -1
  12. package/lib/platform/template/wx/component-config/movable-view.js +18 -1
  13. package/lib/platform/template/wx/component-config/navigator.js +8 -0
  14. package/lib/platform/template/wx/component-config/picker-view-column.js +8 -0
  15. package/lib/platform/template/wx/component-config/picker-view.js +18 -2
  16. package/lib/platform/template/wx/component-config/picker.js +14 -1
  17. package/lib/platform/template/wx/component-config/radio-group.js +8 -0
  18. package/lib/platform/template/wx/component-config/radio.js +8 -0
  19. package/lib/platform/template/wx/component-config/root-portal.js +15 -0
  20. package/lib/platform/template/wx/component-config/switch.js +8 -0
  21. package/lib/platform/template/wx/component-config/unsupported.js +1 -3
  22. package/lib/react/processScript.js +2 -0
  23. package/lib/react/processStyles.js +1 -0
  24. package/lib/react/processTemplate.js +2 -3
  25. package/lib/react/style-helper.js +12 -7
  26. package/lib/runtime/components/react/context.ts +40 -0
  27. package/lib/runtime/components/react/dist/context.js +8 -0
  28. package/lib/runtime/components/react/dist/getInnerListeners.js +34 -12
  29. package/lib/runtime/components/react/dist/mpx-button.jsx +88 -88
  30. package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +82 -0
  31. package/lib/runtime/components/react/dist/mpx-checkbox.jsx +139 -0
  32. package/lib/runtime/components/react/dist/mpx-form.jsx +61 -0
  33. package/lib/runtime/components/react/dist/mpx-icon.jsx +48 -0
  34. package/lib/runtime/components/react/dist/mpx-image/index.jsx +39 -43
  35. package/lib/runtime/components/react/dist/mpx-image/svg.jsx +3 -2
  36. package/lib/runtime/components/react/dist/mpx-input.jsx +63 -37
  37. package/lib/runtime/components/react/dist/mpx-label.jsx +55 -0
  38. package/lib/runtime/components/react/dist/mpx-movable-area.jsx +41 -0
  39. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +346 -0
  40. package/lib/runtime/components/react/dist/mpx-navigator.jsx +35 -0
  41. package/lib/runtime/components/react/dist/mpx-picker/date.jsx +69 -0
  42. package/lib/runtime/components/react/dist/mpx-picker/index.jsx +138 -0
  43. package/lib/runtime/components/react/dist/mpx-picker/multiSelector.jsx +142 -0
  44. package/lib/runtime/components/react/dist/mpx-picker/region.jsx +94 -0
  45. package/lib/runtime/components/react/dist/mpx-picker/regionData.js +6099 -0
  46. package/lib/runtime/components/react/dist/mpx-picker/selector.jsx +76 -0
  47. package/lib/runtime/components/react/dist/mpx-picker/time.jsx +244 -0
  48. package/lib/runtime/components/react/dist/mpx-picker/type.js +1 -0
  49. package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +107 -0
  50. package/lib/runtime/components/react/dist/mpx-picker-view.jsx +162 -0
  51. package/lib/runtime/components/react/dist/mpx-radio-group.jsx +80 -0
  52. package/lib/runtime/components/react/dist/mpx-radio.jsx +154 -0
  53. package/lib/runtime/components/react/dist/mpx-root-portal.jsx +15 -0
  54. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +93 -70
  55. package/lib/runtime/components/react/dist/mpx-swiper/carouse.jsx +281 -157
  56. package/lib/runtime/components/react/dist/mpx-swiper/index.jsx +21 -11
  57. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +19 -11
  58. package/lib/runtime/components/react/dist/mpx-switch.jsx +79 -0
  59. package/lib/runtime/components/react/dist/mpx-text.jsx +21 -49
  60. package/lib/runtime/components/react/dist/mpx-textarea.jsx +2 -2
  61. package/lib/runtime/components/react/dist/mpx-view.jsx +451 -146
  62. package/lib/runtime/components/react/dist/mpx-web-view.jsx +17 -20
  63. package/lib/runtime/components/react/dist/parser.js +218 -0
  64. package/lib/runtime/components/react/dist/types/common.js +1 -0
  65. package/lib/runtime/components/react/dist/useNodesRef.js +3 -8
  66. package/lib/runtime/components/react/dist/utils.jsx +433 -0
  67. package/lib/runtime/components/react/getInnerListeners.ts +43 -21
  68. package/lib/runtime/components/react/mpx-button.tsx +129 -119
  69. package/lib/runtime/components/react/mpx-checkbox-group.tsx +152 -0
  70. package/lib/runtime/components/react/mpx-checkbox.tsx +234 -0
  71. package/lib/runtime/components/react/mpx-form.tsx +117 -0
  72. package/lib/runtime/components/react/mpx-icon.tsx +106 -0
  73. package/lib/runtime/components/react/mpx-image/index.tsx +62 -68
  74. package/lib/runtime/components/react/mpx-image/svg.tsx +7 -5
  75. package/lib/runtime/components/react/mpx-input.tsx +90 -42
  76. package/lib/runtime/components/react/mpx-label.tsx +110 -0
  77. package/lib/runtime/components/react/mpx-movable-area.tsx +81 -0
  78. package/lib/runtime/components/react/mpx-movable-view.tsx +424 -0
  79. package/lib/runtime/components/react/mpx-navigator.tsx +67 -0
  80. package/lib/runtime/components/react/mpx-picker/date.tsx +82 -0
  81. package/lib/runtime/components/react/mpx-picker/index.tsx +155 -0
  82. package/lib/runtime/components/react/mpx-picker/multiSelector.tsx +156 -0
  83. package/lib/runtime/components/react/mpx-picker/region.tsx +107 -0
  84. package/lib/runtime/components/react/mpx-picker/regionData.ts +6101 -0
  85. package/lib/runtime/components/react/mpx-picker/selector.tsx +91 -0
  86. package/lib/runtime/components/react/mpx-picker/time.tsx +270 -0
  87. package/lib/runtime/components/react/mpx-picker/type.ts +107 -0
  88. package/lib/runtime/components/react/mpx-picker-view-column.tsx +156 -0
  89. package/lib/runtime/components/react/mpx-picker-view.tsx +220 -0
  90. package/lib/runtime/components/react/mpx-radio-group.tsx +150 -0
  91. package/lib/runtime/components/react/mpx-radio.tsx +230 -0
  92. package/lib/runtime/components/react/mpx-root-portal.tsx +27 -0
  93. package/lib/runtime/components/react/mpx-scroll-view.tsx +184 -130
  94. package/lib/runtime/components/react/mpx-swiper/carouse.tsx +308 -183
  95. package/lib/runtime/components/react/mpx-swiper/index.tsx +27 -19
  96. package/lib/runtime/components/react/mpx-swiper/type.ts +23 -5
  97. package/lib/runtime/components/react/mpx-swiper-item.tsx +49 -14
  98. package/lib/runtime/components/react/mpx-switch.tsx +148 -0
  99. package/lib/runtime/components/react/mpx-text.tsx +53 -77
  100. package/lib/runtime/components/react/mpx-textarea.tsx +3 -3
  101. package/lib/runtime/components/react/mpx-view.tsx +576 -195
  102. package/lib/runtime/components/react/mpx-web-view.tsx +34 -39
  103. package/lib/runtime/components/react/parser.ts +245 -0
  104. package/lib/runtime/components/react/types/common.ts +12 -0
  105. package/lib/runtime/components/react/types/getInnerListeners.ts +2 -1
  106. package/lib/runtime/components/react/types/global.d.ts +17 -1
  107. package/lib/runtime/components/react/useNodesRef.ts +4 -10
  108. package/lib/runtime/components/react/utils.tsx +505 -0
  109. package/lib/runtime/optionProcessor.js +19 -17
  110. package/lib/template-compiler/compiler.js +84 -61
  111. package/lib/template-compiler/gen-node-react.js +7 -9
  112. package/lib/web/processStyles.js +2 -5
  113. package/package.json +8 -3
  114. package/lib/runtime/components/react/dist/utils.js +0 -80
  115. package/lib/runtime/components/react/utils.ts +0 -92
@@ -1,21 +1,25 @@
1
1
  /**
2
2
  * swiper 实现
3
3
  */
4
- import { View, ScrollView, Dimensions, LayoutChangeEvent, NativeSyntheticEvent, NativeScrollEvent, NativeScrollPoint } from 'react-native'
5
- import React, { forwardRef, useState, useRef, useEffect, ReactNode } from 'react'
4
+ import { Animated, View, ScrollView, Dimensions, NativeSyntheticEvent, NativeScrollEvent, NativeScrollPoint, Platform, LayoutChangeEvent } from 'react-native'
5
+ import { JSX, forwardRef, useState, useRef, useEffect, ReactNode } from 'react'
6
6
  import { CarouseProps, CarouseState } from './type'
7
7
  import { getCustomEvent } from '../getInnerListeners'
8
8
  import useNodesRef, { HandlerRef } from '../useNodesRef' // 引入辅助函数
9
+ import { useTransformStyle, splitStyle, splitProps, useLayout, wrapChildren } from '../utils'
9
10
 
10
11
  /**
11
12
  * 默认的Style类型
12
13
  */
13
14
  const styles: { [key: string]: Object } = {
15
+ slide: {
16
+ backgroundColor: 'transparent'
17
+ },
14
18
  container_x: {
15
- position: 'relative',
19
+ position: 'relative'
16
20
  },
17
21
  container_y: {
18
- position: 'relative',
22
+ position: 'relative'
19
23
  },
20
24
  pagination_x: {
21
25
  position: 'absolute',
@@ -25,7 +29,7 @@ const styles: { [key: string]: Object } = {
25
29
  flexDirection: 'row',
26
30
  flex: 1,
27
31
  justifyContent: 'center',
28
- alignItems: 'center',
32
+ alignItems: 'center'
29
33
  },
30
34
 
31
35
  pagination_y: {
@@ -36,30 +40,62 @@ const styles: { [key: string]: Object } = {
36
40
  flexDirection: 'column',
37
41
  flex: 1,
38
42
  justifyContent: 'center',
39
- alignItems: 'center',
43
+ alignItems: 'center'
40
44
  }
41
45
  }
42
46
 
43
-
44
- const _Carouse = forwardRef<HandlerRef<ScrollView, CarouseProps>, CarouseProps>((props , ref): React.JSX.Element => {
47
+ const _Carouse = forwardRef<HandlerRef<ScrollView & View, CarouseProps>, CarouseProps>((props, ref): JSX.Element => {
45
48
  // 默认取水平方向的width
46
49
  const { width } = Dimensions.get('window')
47
- const defaultHeight = 150
50
+ const {
51
+ style,
52
+ previousMargin = 0,
53
+ nextMargin = 0,
54
+ enableVar,
55
+ externalVarContext,
56
+ parentFontSize,
57
+ parentWidth,
58
+ parentHeight
59
+ } = props
60
+ // 计算transfrom之类的
61
+ const {
62
+ normalStyle,
63
+ hasVarDec,
64
+ varContextRef,
65
+ hasSelfPercent,
66
+ setWidth,
67
+ setHeight
68
+ } = useTransformStyle(style, {
69
+ enableVar,
70
+ externalVarContext,
71
+ parentFontSize,
72
+ parentWidth,
73
+ parentHeight
74
+ })
75
+ const { textStyle, innerStyle } = splitStyle(normalStyle)
76
+ const { textProps } = splitProps(props)
77
+ const newChild = Array.isArray(props.children) ? props.children.filter(child => child) : props.children
78
+ const totalElements = Array.isArray(newChild) ? newChild.length : (newChild ? 1 : 0)
79
+ const defaultHeight = (normalStyle?.height || 150)
80
+ const defaultWidth = (normalStyle?.width || width || 375)
48
81
  const dir = props.horizontal === false ? 'y' : 'x'
49
82
  // state的offset默认值
50
- const defaultX = width * (props.circular ? props.current + 1 : props.current) || 0
51
- const defaultY = defaultHeight * (props.circular ? props.current + 1 : props.current) || 0
83
+ // const initIndex = props.circular ? props.current + 1: (props.current || 0)
84
+ // 记录真正的下标索引, 不包括循环前后加入的索引, 游标
85
+ const initIndex = props.current || 0
86
+ // 这里要排除超过元素个数的设置
87
+ const initOffsetIndex = initIndex + (props.circular && totalElements > 1 ? 1 : 0)
88
+ const defaultX = (defaultWidth * initOffsetIndex) || 0
89
+ const defaultY = (defaultHeight * initOffsetIndex) || 0
52
90
  // 内部存储上一次的offset值
53
- const newChild = Array.isArray(props.children) ? props.children.filter(child => child) : props.children
54
- // 默认设置为初次渲染
55
- const initRenderRef = useRef(true)
56
91
  const autoplayTimerRef = useRef<ReturnType <typeof setTimeout> | null>(null)
57
- let loopJumpTimerRef = useRef<ReturnType <typeof setTimeout> | null>(null)
58
- const { nodeRef: scrollViewRef } = useNodesRef<ScrollView, CarouseProps>(props, ref, {
59
- })
60
- const autoplayEndRef = useRef(false)
61
- // 存储layout布局信息
62
- const layoutRef = useRef({})
92
+ const { nodeRef: scrollViewRef } = useNodesRef<ScrollView & View, CarouseProps>(props, ref, {})
93
+ const {
94
+ // 存储layout布局信息
95
+ layoutRef,
96
+ layoutProps,
97
+ layoutStyle
98
+ } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef: scrollViewRef, onLayout: onWrapperLayout })
63
99
  // 内部存储上一次的偏移量
64
100
  const internalsRef = useRef({
65
101
  offset: {
@@ -68,125 +104,194 @@ const _Carouse = forwardRef<HandlerRef<ScrollView, CarouseProps>, CarouseProps>(
68
104
  },
69
105
  isScrolling: false
70
106
  })
107
+ const isDragRef = useRef(false)
71
108
  const [state, setState] = useState({
72
109
  children: newChild,
73
- width: width || 375,
74
- height: defaultHeight,
75
- index: 0,
76
- total: Array.isArray(newChild) ? newChild.length : ( newChild ? 1 : 0),
110
+ width: dir === 'x' && typeof defaultWidth === 'number' ? defaultWidth - previousMargin - nextMargin : defaultWidth,
111
+ height: dir === 'y' && typeof defaultHeight === 'number' ? defaultHeight - previousMargin - nextMargin : defaultHeight,
112
+ // 真正的游标索引, 从0开始
113
+ index: initIndex,
114
+ total: totalElements,
77
115
  offset: {
78
116
  x: dir === 'x' ? defaultX : 0,
79
- y: dir === 'y' ? defaultY: 0
117
+ y: dir === 'y' ? defaultY : 0
80
118
  },
81
- loopJump: false,
82
119
  dir
83
- } as CarouseState);
120
+ } as CarouseState)
121
+ /**
122
+ * @desc: 开启下一次自动轮播
123
+ */
124
+ function createAutoPlay () {
125
+ autoplayTimerRef.current && clearTimeout(autoplayTimerRef.current)
126
+ autoplayTimerRef.current = setTimeout(() => {
127
+ startAutoPlay()
128
+ }, props.interval || 500)
129
+ }
84
130
 
85
131
  useEffect(() => {
86
132
  // 确认这个是变化的props变化的时候才执行,还是初始化的时候就执行
87
133
  if (props.autoplay) {
88
- startAutoPlay()
89
- } else {
90
- startSwiperLoop()
134
+ createAutoPlay()
91
135
  }
92
- }, [props.autoplay, props.current, state.index]);
136
+ }, [props.autoplay, props.current, state.index, state.width, state.height])
93
137
 
138
+ useEffect(() => {
139
+ // 确认这个是变化的props变化的时候才执行,还是初始化的时候就执行
140
+ if (!props.autoplay && props.current !== state.index) {
141
+ const initIndex = props.current || 0
142
+ // 这里要排除超过元素个数的设置
143
+ const initOffsetIndex = initIndex + (props.circular && totalElements > 1 ? 1 : 0)
144
+ const defaultX = (defaultWidth * initOffsetIndex) || 0
145
+ const offset = {
146
+ x: dir === 'x' ? defaultX : 0,
147
+ y: dir === 'y' ? defaultY : 0
148
+ }
149
+ state.offset = offset
150
+ internalsRef.current.offset = offset
151
+ setState((preState) => {
152
+ return {
153
+ ...preState,
154
+ offset
155
+ }
156
+ })
157
+ }
158
+ }, [props.current])
94
159
  /**
95
- * 更新index,以视图的offset计算当前的索引
160
+ * @desc: 更新状态: indexoffset, 并响应索引变化的事件
161
+ * scrollViewOffset: 移动到的目标位置
96
162
  */
97
- function updateIndex (scrollViewOffset: NativeScrollPoint) {
98
- const diff = scrollViewOffset[dir] - internalsRef.current.offset[state.dir]
99
- if (!diff) return
163
+ function updateIndex (scrollViewOffset: NativeScrollPoint, useIndex = false) {
164
+ const { nextIndex, nextOffset } = getNextConfig(scrollViewOffset)
165
+ updateState(nextIndex, nextOffset)
166
+ // 更新完状态之后, 开启新的loop
167
+ }
100
168
 
101
- const step = dir === 'x' ? state.width : state.height
102
- let loopJump = false
103
- let newIndex = state.index + Math.round(diff / step)
104
- // 若是循环circular
105
- // 1. 当前索引-1, 初始化为最后一个索引, 且scrollView的偏移量设置为 每个元素的步长 * 一共多少个元素, 这里为什么不减一呢
106
- // 2. 当前索引>total, 初始化为第一个元素,且scrollView的偏移量设置为一个元素的步长
107
- if (props.circular) {
108
- if (state.index <= -1) {
109
- newIndex = state.total - 1
110
- scrollViewOffset[state.dir] = step * state.total
111
- loopJump = true
112
- } else if (newIndex >= state.total) {
113
- newIndex = 0
114
- scrollViewOffset[state.dir] = step
115
- loopJump = true
116
- }
117
- }
118
- // 存储当前的偏移量
119
- internalsRef.current.offset = scrollViewOffset
120
- // 这里需不需要区分是否loop,初始化????
169
+ /**
170
+ * 更新索引状态
171
+ */
172
+ function updateState (index: number, offset: { x: number, y: number}) {
173
+ internalsRef.current.offset = offset
121
174
  setState((preState) => {
122
- const newState = {
175
+ const newState = {
123
176
  ...preState,
124
- index: newIndex,
125
- offset: scrollViewOffset,
126
- loopJump
177
+ index: index,
178
+ // offset用来指示当前scrollView的偏移量
179
+ offset: offset
127
180
  }
128
181
  return newState
129
182
  })
130
183
  internalsRef.current.isScrolling = false
131
184
  // getCustomEvent
132
- const eventData = getCustomEvent('change', {}, { detail: {current: newIndex, source: 'touch' }, layoutRef: layoutRef })
185
+ const eventData = getCustomEvent('change', {}, { detail: { current: index, source: 'touch' }, layoutRef: layoutRef })
133
186
  props.bindchange && props.bindchange(eventData)
134
- // 更新完状态之后, 开启新的loop
135
187
  }
136
188
 
137
189
  /**
138
- * 用户手动点击播放
139
- * 触发scrollView的onScrollEnd事件 => 然后更新索引 => 通过useEffect事件 => startSwiperLoop => 主动更新scrollView到指定的位置
140
- * 若是circular, 到最后一个索引会更新为0,但是视觉要scrollView到下一个
141
- * 若是circular, 到第一个再往前索引会更新为total-1, 但是视觉是展示的最后一个
190
+ * @desc: 获取下一个位置的索引、scrollView的contentOffset、scrollTo到的offset
191
+ * @desc: 包括正循环、反向循环、不循环
192
+ * 其中循环模式为了实现无缝链接, 会将结合contentOffset, 和 scrollTo的offset,
193
+ * 先scrollTo一个位置的坐标, 然后通过updateIndex设置真正的index和内容的offset,视觉上是无缝
142
194
  */
143
- function startSwiperLoop () {
144
- loopJumpTimerRef.current = setTimeout(() => {
145
- let offset = { x: 0, y: 0, animated: false}
146
- if (state.index > 0){
147
- offset = props.horizontal ? { x: state.width * state.index, y: 0, animated: false } : { x: 0, y: state.height * state.index, animated: false }
148
- }
149
- if (props.circular) {
150
- offset = props.horizontal ? { x: state.width * (state.index + 1), y: 0, animated: false } : { x: 0, y: state.height * (state.index + 1), animated: false }
195
+ function getNextConfig (scrollViewOffset: NativeScrollPoint) {
196
+ const step = state.dir === 'x' ? state.width : state.height
197
+ const currentOffset = state.offset
198
+ let nextIndex = state.index + 1
199
+ let nextOffset = currentOffset
200
+ // autoMoveOffset scrollView 滚动到前后增加的位置
201
+ let autoMoveOffset = currentOffset
202
+ let isBack = false
203
+ let isAutoEnd = false
204
+ // 如果是循环反向的
205
+ if (scrollViewOffset?.[state.dir] < currentOffset[state.dir]) {
206
+ isBack = true
207
+ nextIndex = isBack ? nextIndex - 2 : nextIndex
208
+ }
209
+ if (!props.circular) {
210
+ // nextIndex = isBack ? nextIndex - 2 : nextIndex
211
+ nextOffset = Object.assign({}, currentOffset, { [state.dir]: step * nextIndex })
212
+ } else {
213
+ if (isBack) {
214
+ if (nextIndex < 0) {
215
+ // 反向: scollView 滚动到虚拟的位置
216
+ autoMoveOffset = Object.assign({}, currentOffset, { [state.dir]: 0 })
217
+ nextIndex = state.total - 1
218
+ // 反向: 数组最后一个index
219
+ nextOffset = Object.assign({}, currentOffset, { [state.dir]: step * state.total })
220
+ isAutoEnd = true
221
+ } else {
222
+ // 反向非最后一个
223
+ nextOffset = Object.assign({}, currentOffset, { [state.dir]: (nextIndex + 1) * step })
224
+ }
225
+ } else {
226
+ if (nextIndex > state.total - 1) {
227
+ autoMoveOffset = Object.assign({}, currentOffset, { [state.dir]: step * (nextIndex + 1) })
228
+ nextIndex = 0
229
+ nextOffset = Object.assign({}, currentOffset, { [state.dir]: step })
230
+ isAutoEnd = true
231
+ } else {
232
+ // nextIndex = nextIndex,
233
+ nextOffset = Object.assign({}, currentOffset, { [state.dir]: (nextIndex + 1) * step })
234
+ }
151
235
  }
152
- scrollViewRef.current?.scrollTo(offset)
153
- internalsRef.current.offset = offset
154
- }, props.duration || 500)
236
+ }
237
+ return {
238
+ // 下一个要滚动到的实际元素的索引
239
+ nextIndex,
240
+ // 下一个要滚动到实际元素的offset
241
+ nextOffset,
242
+ // scrollTo一个位置的坐标, 虚拟元素的位置
243
+ autoMoveOffset,
244
+ isAutoEnd
245
+ }
155
246
  }
156
247
 
157
248
  /**
158
- * 开启自动轮播
159
- * 每间隔interval scrollView的offset更改到下一个位置,通过onScrollEnd来获取contentOffset再计算要更新的索引index
249
+ * @desc: 开启自动轮播
160
250
  */
161
251
  function startAutoPlay () {
162
- // 已经开启过autopaly则不重新创建
163
- if (!Array.isArray(state.children) || !props.autoplay || internalsRef.current.isScrolling || autoplayEndRef.current) {
252
+ if (state.width && isNaN(+state.width)) {
253
+ createAutoPlay()
164
254
  return
165
255
  }
166
- autoplayTimerRef.current && clearTimeout(autoplayTimerRef.current)
167
- // 非循环自动播放的形式下 到最后一帧 结束自动播放
168
- if (!props.circular && state.index === state.total -1) {
169
- autoplayEndRef.current = true
256
+ if (!Array.isArray(state.children)) {
170
257
  return
171
258
  }
172
-
173
- // 开启自动播放
174
- autoplayTimerRef.current = setTimeout(() => {
175
- if (state.total < 2) return
176
- const nexStep = 1
177
- const toIndex = (props.circular ? 1 : 0) + nexStep + state.index
178
- let x = 0
179
- let y = 0
180
- if (state.dir === 'x') x = toIndex * state.width
181
- if (state.dir === 'y') y = toIndex * state.height
182
- // animated会影响切换的offset,先改为false
183
- scrollViewRef.current?.scrollTo({ x, y, animated: false })
184
-
185
- internalsRef.current.isScrolling = true
186
-
187
- autoplayEndRef.current = false
188
- updateIndex({ x, y })
189
- }, props.interval || 5000)
259
+ const step = state.dir === 'x' ? state.width : state.height
260
+ const { nextOffset, autoMoveOffset, isAutoEnd } = getNextConfig(state.offset)
261
+ // 这里可以scroll到下一个元素, 但是把scrollView的偏移量在设置为content,视觉效果就没了吧
262
+ // scrollViewRef.current?.scrollTo({ x: nextOffset['x'], y: nextOffset['y'], animated: true })
263
+ if (Platform.OS === 'ios') {
264
+ if (!isAutoEnd) {
265
+ scrollViewRef.current?.scrollTo({ x: nextOffset.x, y: nextOffset.y, animated: true })
266
+ } else {
267
+ if (state.dir === 'x') {
268
+ scrollViewRef.current?.scrollTo({ x: autoMoveOffset.x, y: autoMoveOffset.x, animated: true })
269
+ } else {
270
+ scrollViewRef.current?.scrollTo({ x: autoMoveOffset.y, y: autoMoveOffset.y, animated: true })
271
+ }
272
+ }
273
+ } else {
274
+ if (!isAutoEnd) {
275
+ scrollViewRef.current?.scrollTo({ x: nextOffset.x, y: nextOffset.y, animated: true })
276
+ onScrollEnd({
277
+ nativeEvent: {
278
+ contentOffset: {
279
+ x: +nextOffset.x,
280
+ y: +nextOffset.y
281
+ }
282
+ }
283
+ } as NativeSyntheticEvent<NativeScrollEvent>)
284
+ } else {
285
+ // 安卓无法实现视觉的无缝连接, 只能回到真正的位置, 且安卓调用scrollTo不能触发onMomentumScrollEnd,还未找到为啥
286
+ if (state.dir === 'x') {
287
+ scrollViewRef.current?.scrollTo({ x: step, y: step, animated: true })
288
+ // scrollViewRef.current?.scrollTo({ x: autoMoveOffset.x, y: autoMoveOffset.y, animated: true })
289
+ } else {
290
+ scrollViewRef.current?.scrollTo({ x: autoMoveOffset.x, y: step, animated: true })
291
+ }
292
+ updateState(0, nextOffset)
293
+ }
294
+ }
190
295
  }
191
296
 
192
297
  /**
@@ -195,11 +300,18 @@ const _Carouse = forwardRef<HandlerRef<ScrollView, CarouseProps>, CarouseProps>(
195
300
  function onScrollBegin () {
196
301
  internalsRef.current.isScrolling = true
197
302
  }
303
+
304
+ /**
305
+ * 当用户开始拖动结束
306
+ */
198
307
  function onScrollEnd (event: NativeSyntheticEvent<NativeScrollEvent>) {
308
+ // 这里安卓好像没有触发onScrollEnd, 调用scrollTo的时候
309
+ if (totalElements === 1) {
310
+ return
311
+ }
199
312
  internalsRef.current.isScrolling = false
200
-
201
313
  // 用户手动滑动更新索引后,如果开启了自动轮播等重新开始
202
- updateIndex(event.nativeEvent.contentOffset)
314
+ updateIndex(event.nativeEvent.contentOffset, true)
203
315
  }
204
316
 
205
317
  /**
@@ -208,66 +320,82 @@ const _Carouse = forwardRef<HandlerRef<ScrollView, CarouseProps>, CarouseProps>(
208
320
  function onScrollEndDrag (event: NativeSyntheticEvent<NativeScrollEvent>) {
209
321
  const { contentOffset } = event.nativeEvent
210
322
  const { index, total } = state
211
-
323
+ isDragRef.current = true
212
324
  const internalOffset = internalsRef.current.offset
213
325
  const previousOffset = props.horizontal ? internalOffset.x : internalOffset.y
214
- const newOffset = props.horizontal ? contentOffset.x : contentOffset.y
215
-
216
- if (previousOffset === newOffset && (index === 0 || index === total - 1)) {
326
+ const moveOffset = props.horizontal ? contentOffset.x : contentOffset.y
327
+ if (previousOffset === moveOffset && (index === 0 || index === total - 1)) {
217
328
  internalsRef.current.isScrolling = false
218
329
  }
219
330
  }
220
- /**
221
- * 垂直方向时,获取单个元素的布局,更新
222
- */
223
- function onItemLayout (event: LayoutChangeEvent) {
224
- if (!initRenderRef.current || state.dir === 'x') return
225
- const { width, height } = event.nativeEvent.layout
226
- if (state.total > 1) {
227
- internalsRef.current.offset[state.dir] = (state.dir === 'y' ? height * state.index : state.width * state.index)
228
- }
229
331
 
230
- if (!state.offset.x && !state.offset.y) {
231
- state.offset = internalsRef.current.offset
232
- }
233
-
234
- if (initRenderRef.current && state.total > 1) {
235
- scrollViewRef.current?.scrollTo({ ...internalsRef.current.offset, animated: false })
236
- initRenderRef.current = false
237
- }
238
- setState((preState) => {
239
- return {
240
- ...preState,
241
- height
242
- }
243
- })
244
- }
245
332
  /**
246
- * 水平方向时,获取单个元素的布局,更新
333
+ * @desc: 水平方向时,获取元素的布局,更新, 其中如果传递100%时需要依赖measure计算元算的宽高
247
334
  */
248
- function onWrapperLayout () {
335
+ function onWrapperLayout (e: LayoutChangeEvent) {
336
+ if (hasSelfPercent) {
337
+ const { width, height } = e?.nativeEvent?.layout || {}
338
+ setWidth(width || 0)
339
+ setHeight(height || 0)
340
+ }
249
341
  if (props.enableOffset) {
250
- // @ts-ignore
251
342
  scrollViewRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => {
252
343
  layoutRef.current = { x, y, width, height, offsetLeft, offsetTop }
344
+ const isWDiff = state.width !== width
345
+ const isHDiff = state.height !== height
346
+ if (isWDiff || isHDiff) {
347
+ const changeState = {
348
+ width: isWDiff ? width : state.width,
349
+ height: isHDiff ? height : state.height
350
+ }
351
+ const attr = state.dir === 'x' ? 'width' : 'height'
352
+ changeState[attr] = changeState[attr] - previousMargin - nextMargin
353
+ const correctOffset = Object.assign({}, state.offset, {
354
+ [state.dir]: initOffsetIndex * (state.dir === 'x' ? changeState.width : changeState.height)
355
+ })
356
+ state.offset = correctOffset
357
+ state.width = changeState.width
358
+ state.height = changeState.height
359
+ setState((preState) => {
360
+ return {
361
+ ...preState,
362
+ offset: correctOffset,
363
+ width: changeState.width,
364
+ height: changeState.height
365
+ }
366
+ })
367
+ scrollViewRef.current?.scrollTo({ x: correctOffset.x, y: correctOffset.y, animated: false })
368
+ }
253
369
  props.getInnerLayout && props.getInnerLayout(layoutRef)
254
370
  })
255
371
  }
256
- if (state.dir === 'y') return
257
- if (!state.offset.x && !state.offset.y) {
258
- state.offset = internalsRef.current.offset
259
- }
260
- if (!initRenderRef.current && state.total > 1) {
261
- scrollViewRef.current?.scrollTo({ ...state.offset, animated: false })
262
- initRenderRef.current = false
372
+ }
373
+
374
+ function getOffset (): Array<number> {
375
+ const step = state.dir === 'x' ? state.width : state.height
376
+ if (!step || Number.isNaN(+step)) return []
377
+ const offsetArray = []
378
+ if (previousMargin) {
379
+ offsetArray.push(0)
380
+ for (let i = 1; i < totalElements; i++) {
381
+ offsetArray.push(i * step - previousMargin)
382
+ }
383
+ } else {
384
+ for (let i = 0; i < totalElements; i++) {
385
+ offsetArray.push(i * step)
386
+ }
263
387
  }
388
+ return offsetArray
264
389
  }
265
390
 
266
391
  function renderScrollView (pages: ReactNode) {
267
- let scrollElementProps = {
392
+ const offsetsArray = getOffset()
393
+ const scrollElementProps = {
268
394
  ref: scrollViewRef,
269
395
  horizontal: props.horizontal,
270
- pagingEnabled: true,
396
+ pagingEnabled: false,
397
+ snapToOffsets: offsetsArray,
398
+ decelerationRate: 0.99, // 'fast'
271
399
  showsHorizontalScrollIndicator: false,
272
400
  showsVerticalScrollIndicator: false,
273
401
  bounces: false,
@@ -275,9 +403,11 @@ const _Carouse = forwardRef<HandlerRef<ScrollView, CarouseProps>, CarouseProps>(
275
403
  removeClippedSubviews: true,
276
404
  automaticallyAdjustContentInsets: false
277
405
  }
406
+ const layoutStyle = dir === 'x' ? { width: defaultWidth, height: defaultHeight } : { width: defaultWidth }
278
407
  return (
279
- <ScrollView
408
+ <Animated.ScrollView
280
409
  {...scrollElementProps}
410
+ style={[layoutStyle]}
281
411
  overScrollMode="always"
282
412
  contentOffset={state.offset}
283
413
  onScrollBeginDrag={onScrollBegin}
@@ -285,14 +415,14 @@ const _Carouse = forwardRef<HandlerRef<ScrollView, CarouseProps>, CarouseProps>(
285
415
  onScrollEndDrag={onScrollEndDrag}
286
416
  >
287
417
  {pages}
288
- </ScrollView>
418
+ </Animated.ScrollView>
289
419
  )
290
420
  }
291
421
 
292
422
  function renderPagination () {
293
423
  if (state.total <= 1) return null
294
- let dots: Array<ReactNode> = []
295
- const activeDotStyle = [ {
424
+ const dots: Array<ReactNode> = []
425
+ const activeDotStyle = [{
296
426
  backgroundColor: props.activeDotColor || '#007aff',
297
427
  width: 8,
298
428
  height: 8,
@@ -331,68 +461,63 @@ const _Carouse = forwardRef<HandlerRef<ScrollView, CarouseProps>, CarouseProps>(
331
461
 
332
462
  function renderPages () {
333
463
  const { width, height, total, children } = state
334
- const { circular, previousMargin, nextMargin, innerProps } = props
464
+ const { circular } = props
335
465
  const pageStyle = { width: width, height: height }
466
+ // 设置了previousMargin或者nextMargin,
467
+ // 1. 元素的宽度是减去这两个数目之和
468
+ // 2. previousMargin设置marginLeft正值, nextmargin设置marginRight负值
469
+ // 3. 第一个元素设置previousMargin 和 nextMargin, 最后一个元素
336
470
  if (total > 1 && Array.isArray(children)) {
337
471
  let arrElements: (Array<ReactNode>) = []
338
472
  // pages = ["2", "0", "1", "2", "0"]
339
- let pages = Array.isArray(children) && Object.keys(children) || []
473
+ const pages = Array.isArray(children) ? Object.keys(children) : []
340
474
  /* 无限循环的时候 */
341
475
  if (circular) {
342
476
  pages.unshift(total - 1 + '')
343
477
  pages.push('0')
344
478
  }
345
479
  arrElements = pages.map((page, i) => {
346
- let pageStyle2 = { width: width, height: height }
347
480
  const extraStyle = {} as {
348
- left? : number;
349
- marginLeft?: number;
350
- paddingLeft?: number
481
+ [key: string]: any
351
482
  }
352
-
353
- if (previousMargin) {
354
- extraStyle.left = +previousMargin
355
- }
356
- if (nextMargin && state.index === i - 1) {
357
- const half = Math.floor(+nextMargin / 2)
358
- extraStyle.marginLeft = - half
359
- extraStyle.paddingLeft = half
483
+ if (i === 0 && dir === 'x' && typeof width === 'number') {
484
+ previousMargin && (extraStyle.marginLeft = previousMargin)
485
+ } else if (i === pages.length - 1 && typeof width === 'number') {
486
+ nextMargin && (extraStyle.marginRight = nextMargin)
360
487
  }
361
- return (
362
- <View style={[pageStyle2, extraStyle]} key={ 'page' + i} onLayout={onItemLayout}>
363
- {children[+page]}
364
- </View>
365
- )
488
+ // return (<View style={[pageStyle, styles.slide, extraStyle]} key={ 'page' + i}>{children[+page]}</View>)
489
+ return (<View style={[pageStyle, styles.slide, extraStyle]} key={ 'page' + i}>
490
+ {wrapChildren(
491
+ {
492
+ children: children[+page]
493
+ },
494
+ {
495
+ hasVarDec,
496
+ varContext: varContextRef.current,
497
+ textStyle,
498
+ textProps
499
+ }
500
+ )}
501
+ </View>)
366
502
  })
367
503
  return arrElements
368
504
  } else {
369
- return (
505
+ const realElement = (
370
506
  <View style={pageStyle} key={0}>
371
507
  {children}
372
508
  </View>
373
509
  )
510
+ return realElement
374
511
  }
375
512
  }
376
513
 
377
- const vStyle = {} as { height: number }
378
- if (dir === 'y') {
379
- vStyle.height = defaultHeight
380
- }
381
514
  const pages: Array<ReactNode> | ReactNode = renderPages()
382
- const strStyle: string = 'container_' + state.dir
383
- const eventProps = props.innerProps || {}
384
-
385
- return (
386
- <View
387
- style={[styles[strStyle], vStyle]}
388
- {...eventProps}
389
- onLayout={onWrapperLayout}>
515
+ return (<View style={[normalStyle, innerStyle, layoutStyle]} {...layoutProps}>
390
516
  {renderScrollView(pages)}
391
517
  {props.showsPagination && renderPagination()}
392
- </View>)
393
-
518
+ </View>)
394
519
  })
395
520
 
396
- _Carouse.displayName = '_Carouse';
521
+ _Carouse.displayName = '_Carouse'
397
522
 
398
523
  export default _Carouse