@mpxjs/webpack-plugin 2.9.69-beta.1 → 2.9.69-beta.10

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 (51) hide show
  1. package/lib/config.js +3 -1
  2. package/lib/platform/template/wx/index.js +3 -1
  3. package/lib/react/processScript.js +6 -4
  4. package/lib/runtime/components/react/context.ts +17 -0
  5. package/lib/runtime/components/react/dist/context.js +2 -0
  6. package/lib/runtime/components/react/dist/getInnerListeners.js +2 -2
  7. package/lib/runtime/components/react/dist/locale-provider.jsx +15 -0
  8. package/lib/runtime/components/react/dist/mpx-button.jsx +16 -44
  9. package/lib/runtime/components/react/dist/mpx-image.jsx +13 -9
  10. package/lib/runtime/components/react/dist/mpx-picker/time.jsx +2 -1
  11. package/lib/runtime/components/react/dist/mpx-picker-view-column-item.jsx +2 -2
  12. package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +65 -61
  13. package/lib/runtime/components/react/dist/mpx-portal/portal-consumer.jsx +23 -0
  14. package/lib/runtime/components/react/dist/mpx-portal/portal-host.jsx +93 -0
  15. package/lib/runtime/components/react/dist/mpx-portal/portal-manager.jsx +40 -0
  16. package/lib/runtime/components/react/dist/mpx-portal.jsx +13 -0
  17. package/lib/runtime/components/react/dist/mpx-provider.jsx +31 -0
  18. package/lib/runtime/components/react/dist/mpx-root-portal.jsx +1 -1
  19. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +9 -5
  20. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +13 -7
  21. package/lib/runtime/components/react/dist/mpx-swiper.jsx +384 -321
  22. package/lib/runtime/components/react/dist/mpx-view.jsx +16 -20
  23. package/lib/runtime/components/react/dist/mpx-web-view.jsx +129 -53
  24. package/lib/runtime/components/react/dist/pickerFaces.js +2 -7
  25. package/lib/runtime/components/react/dist/useAnimationHooks.js +30 -13
  26. package/lib/runtime/components/react/dist/utils.jsx +60 -2
  27. package/lib/runtime/components/react/getInnerListeners.ts +2 -2
  28. package/lib/runtime/components/react/locale-provider.tsx +83 -0
  29. package/lib/runtime/components/react/mpx-button.tsx +20 -57
  30. package/lib/runtime/components/react/mpx-image.tsx +41 -25
  31. package/lib/runtime/components/react/mpx-picker/time.tsx +2 -1
  32. package/lib/runtime/components/react/mpx-picker-view-column-item.tsx +3 -3
  33. package/lib/runtime/components/react/mpx-picker-view-column.tsx +70 -69
  34. package/lib/runtime/components/react/mpx-portal/portal-consumer.tsx +32 -0
  35. package/lib/runtime/components/react/mpx-portal/portal-host.tsx +127 -0
  36. package/lib/runtime/components/react/mpx-portal/portal-manager.tsx +64 -0
  37. package/lib/runtime/components/react/mpx-portal.tsx +30 -0
  38. package/lib/runtime/components/react/mpx-provider.tsx +51 -0
  39. package/lib/runtime/components/react/mpx-root-portal.tsx +1 -1
  40. package/lib/runtime/components/react/mpx-scroll-view.tsx +10 -8
  41. package/lib/runtime/components/react/mpx-swiper-item.tsx +13 -7
  42. package/lib/runtime/components/react/mpx-swiper.tsx +378 -325
  43. package/lib/runtime/components/react/mpx-view.tsx +19 -22
  44. package/lib/runtime/components/react/mpx-web-view.tsx +170 -62
  45. package/lib/runtime/components/react/pickerFaces.ts +2 -7
  46. package/lib/runtime/components/react/types/global.d.ts +7 -0
  47. package/lib/runtime/components/react/useAnimationHooks.ts +34 -14
  48. package/lib/runtime/components/react/utils.tsx +67 -2
  49. package/lib/template-compiler/compiler.js +1 -1
  50. package/lib/wxss/loader.js +15 -2
  51. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  import { View } from 'react-native';
2
2
  import { GestureDetector, Gesture } from 'react-native-gesture-handler';
3
- import Animated, { useAnimatedStyle, useSharedValue, withTiming, Easing, runOnJS, runOnUI, useAnimatedReaction, cancelAnimation } from 'react-native-reanimated';
4
- import React, { forwardRef, useRef, useEffect } from 'react';
3
+ import Animated, { useAnimatedStyle, useSharedValue, withTiming, Easing, runOnJS, useAnimatedReaction, cancelAnimation } from 'react-native-reanimated';
4
+ import React, { forwardRef, useRef, useEffect, useMemo } from 'react';
5
5
  import useInnerProps, { getCustomEvent } from './getInnerListeners';
6
6
  import useNodesRef from './useNodesRef'; // 引入辅助函数
7
7
  import { useTransformStyle, splitStyle, splitProps, useLayout, wrapChildren } from './utils';
@@ -63,21 +63,17 @@ const activeDotStyle = {
63
63
  };
64
64
  const longPressRatio = 100;
65
65
  const easeMap = {
66
- default: Easing.linear,
66
+ default: Easing.inOut(Easing.poly(3)),
67
67
  linear: Easing.linear,
68
68
  easeInCubic: Easing.in(Easing.cubic),
69
69
  easeOutCubic: Easing.out(Easing.cubic),
70
70
  easeInOutCubic: Easing.inOut(Easing.cubic)
71
71
  };
72
72
  const SwiperWrapper = forwardRef((props, ref) => {
73
- const { 'indicator-dots': showsPagination, 'indicator-color': dotColor = 'rgba(0, 0, 0, .3)', 'indicator-active-color': activeDotColor = '#000000', 'enable-var': enableVar = false, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, 'external-var-context': externalVarContext, style = {} } = props;
74
- const previousMargin = props['previous-margin'] ? parseInt(props['previous-margin']) : 0;
75
- const nextMargin = props['next-margin'] ? parseInt(props['next-margin']) : 0;
73
+ const { 'indicator-dots': showsPagination, 'indicator-color': dotColor = 'rgba(0, 0, 0, .3)', 'indicator-active-color': activeDotColor = '#000000', 'enable-var': enableVar = false, 'parent-font-size': parentFontSize, 'parent-width': parentWidth, 'parent-height': parentHeight, 'external-var-context': externalVarContext, style = {}, autoplay = false, circular = false } = props;
76
74
  const easeingFunc = props['easing-function'] || 'default';
77
75
  const easeDuration = props.duration || 500;
78
76
  const horizontal = props.vertical !== undefined ? !props.vertical : true;
79
- // 默认前后补位的元素个数
80
- const patchElementNum = props.circular ? (previousMargin ? 2 : 1) : 0;
81
77
  const nodeRef = useRef(null);
82
78
  useNodesRef(props, ref, nodeRef, {});
83
79
  // 计算transfrom之类的
@@ -90,21 +86,31 @@ const SwiperWrapper = forwardRef((props, ref) => {
90
86
  });
91
87
  const { textStyle } = splitStyle(normalStyle);
92
88
  const { textProps } = splitProps(props);
89
+ const preMargin = props['previous-margin'] ? global.__formatValue(props['previous-margin']) : 0;
90
+ const nextMargin = props['next-margin'] ? global.__formatValue(props['next-margin']) : 0;
91
+ const preMarginShared = useSharedValue(preMargin);
92
+ const nextMarginShared = useSharedValue(nextMargin);
93
+ const autoplayShared = useSharedValue(autoplay);
94
+ // 默认前后补位的元素个数
95
+ const patchElmNum = circular ? (preMargin ? 2 : 1) : 0;
96
+ const patchElmNumShared = useSharedValue(patchElmNum);
97
+ const circularShared = useSharedValue(circular);
93
98
  const children = Array.isArray(props.children) ? props.children.filter(child => child) : (props.children ? [props.children] : []);
94
- const initWidth = typeof normalStyle?.width === 'number' ? normalStyle.width - previousMargin - nextMargin : normalStyle.width;
95
- const initHeight = typeof normalStyle?.height === 'number' ? normalStyle.height - previousMargin - nextMargin : normalStyle.height;
96
- const dir = useSharedValue(horizontal === false ? 'y' : 'x');
97
- const pstep = dir.value === 'x' ? initWidth : initHeight;
99
+ // 对有变化的变量,在worklet中只能使用sharedValue变量,useRef不能更新
100
+ const childrenLength = useSharedValue(children.length);
101
+ const initWidth = typeof normalStyle?.width === 'number' ? normalStyle.width - preMargin - nextMargin : normalStyle.width;
102
+ const initHeight = typeof normalStyle?.height === 'number' ? normalStyle.height - preMargin - nextMargin : normalStyle.height;
103
+ const dir = horizontal === false ? 'y' : 'x';
104
+ const pstep = dir === 'x' ? initWidth : initHeight;
98
105
  const initStep = isNaN(pstep) ? 0 : pstep;
99
- // 每个元素的宽度 or 高度
106
+ // 每个元素的宽度 or 高度,有固定值直接初始化无则0
100
107
  const step = useSharedValue(initStep);
101
- const totalElements = useSharedValue(children.length);
102
108
  // 记录选中元素的索引值
103
- const currentIndex = useSharedValue(0);
109
+ const currentIndex = useSharedValue(props.current || 0);
110
+ // const initOffset = getOffset(props.current || 0, initStep)
104
111
  // 记录元素的偏移量
105
- const offset = useSharedValue(0);
106
- const strAbso = 'absolute' + dir.value.toUpperCase();
107
- const arrPages = renderItems();
112
+ const offset = useSharedValue(getOffset(props.current || 0, initStep));
113
+ const strAbso = 'absolute' + dir.toUpperCase();
108
114
  // 标识手指触摸和抬起, 起点在onBegin
109
115
  const touchfinish = useSharedValue(true);
110
116
  // 记录上一帧的绝对定位坐标
@@ -114,10 +120,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
114
120
  // 记录从onBegin 到 onTouchesUp 的时间
115
121
  const moveTime = useSharedValue(0);
116
122
  const timerId = useRef(0);
117
- // 用户点击未移动状态下,记录用户上一次操作的transtion 的 direction
118
- const customTrans = useSharedValue(0);
119
123
  const intervalTimer = props.interval || 500;
120
- totalElements.value = children.length;
121
124
  const {
122
125
  // 存储layout布局信息
123
126
  layoutRef, layoutProps, layoutStyle } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef, onLayout: onWrapperLayout });
@@ -140,22 +143,20 @@ const SwiperWrapper = forwardRef((props, ref) => {
140
143
  ], { layoutRef: layoutRef });
141
144
  function onWrapperLayout(e) {
142
145
  const { width, height } = e.nativeEvent.layout;
143
- const realWidth = dir.value === 'x' ? width - previousMargin - nextMargin : width;
144
- const realHeight = dir.value === 'y' ? height - previousMargin - nextMargin : height;
145
- step.value = dir.value === 'x' ? realWidth : realHeight;
146
- if (touchfinish.value) {
147
- runOnUI(() => {
148
- offset.value = getOffset(currentIndex.value);
149
- })();
150
- pauseLoop();
151
- resumeLoop();
146
+ const realWidth = dir === 'x' ? width - preMargin - nextMargin : width;
147
+ const realHeight = dir === 'y' ? height - preMargin - nextMargin : height;
148
+ const iStep = dir === 'x' ? realWidth : realHeight;
149
+ if (iStep !== step.value) {
150
+ step.value = iStep;
151
+ updateCurrent(props.current || 0, iStep);
152
+ updateAutoplay();
152
153
  }
153
154
  }
154
155
  const dotAnimatedStyle = useAnimatedStyle(() => {
155
156
  if (!step.value)
156
157
  return {};
157
158
  const dotStep = dotCommonStyle.width + dotCommonStyle.marginRight + dotCommonStyle.marginLeft;
158
- if (dir.value === 'x') {
159
+ if (dir === 'x') {
159
160
  return { transform: [{ translateX: currentIndex.value * dotStep }] };
160
161
  }
161
162
  else {
@@ -163,17 +164,17 @@ const SwiperWrapper = forwardRef((props, ref) => {
163
164
  }
164
165
  });
165
166
  function renderPagination() {
166
- if (totalElements.value <= 1)
167
+ if (children.length <= 1)
167
168
  return null;
168
169
  const activeColor = activeDotColor || '#007aff';
169
170
  const unActionColor = dotColor || 'rgba(0,0,0,.2)';
170
171
  // 正常渲染所有dots
171
172
  const dots = [];
172
- for (let i = 0; i < totalElements.value; i++) {
173
+ for (let i = 0; i < children.length; i++) {
173
174
  dots.push(<View style={[dotCommonStyle, { backgroundColor: unActionColor }]} key={i}></View>);
174
175
  }
175
- return (<View pointerEvents="none" style={styles['pagination_' + dir.value]}>
176
- <View style={[styles['pagerWrapper' + dir.value]]}>
176
+ return (<View pointerEvents="none" style={styles['pagination_' + dir]}>
177
+ <View style={[styles['pagerWrapper' + dir]]}>
177
178
  <Animated.View style={[
178
179
  dotCommonStyle,
179
180
  activeDotStyle,
@@ -190,87 +191,62 @@ const SwiperWrapper = forwardRef((props, ref) => {
190
191
  </View>);
191
192
  }
192
193
  function renderItems() {
193
- const itemAnimatedStyles = useAnimatedStyle(() => {
194
- return dir.value === 'x' ? { width: step.value, height: '100%' } : { width: '100%', height: step.value };
195
- });
194
+ const intLen = children.length;
196
195
  let renderChild = children.slice();
197
- if (props.circular && totalElements.value > 1) {
196
+ if (circular && intLen > 1) {
198
197
  // 最前面加最后一个元素
199
- const lastChild = React.cloneElement(children[totalElements.value - 1]);
198
+ const lastChild = React.cloneElement(children[intLen - 1], { key: 'clone0' });
200
199
  // 最后面加第一个元素
201
- const firstChild = React.cloneElement(children[0]);
202
- if (previousMargin) {
203
- const lastChild1 = React.cloneElement(children[totalElements.value - 2]);
204
- const firstChild1 = React.cloneElement(children[1]);
200
+ const firstChild = React.cloneElement(children[0], { key: 'clone1' });
201
+ if (preMargin) {
202
+ const lastChild1 = React.cloneElement(children[intLen - 2], { key: 'clone2' });
203
+ const firstChild1 = React.cloneElement(children[1], { key: 'clone3' });
205
204
  renderChild = [lastChild1, lastChild].concat(renderChild).concat([firstChild, firstChild1]);
206
205
  }
207
206
  else {
208
207
  renderChild = [lastChild].concat(renderChild).concat([firstChild]);
209
208
  }
210
209
  }
211
- const arrChilds = renderChild.map((child, index) => {
210
+ const arrChildren = renderChild.map((child, index) => {
212
211
  const extraStyle = {};
213
- if (index === 0 && !props.circular) {
214
- previousMargin && dir.value === 'x' && (extraStyle.marginLeft = previousMargin);
215
- previousMargin && dir.value === 'y' && (extraStyle.marginTop = previousMargin);
212
+ if (index === 0 && !circular) {
213
+ preMargin && dir === 'x' && (extraStyle.marginLeft = preMargin);
214
+ preMargin && dir === 'y' && (extraStyle.marginTop = preMargin);
216
215
  }
217
- if (index === totalElements.value - 1 && !props.circular) {
218
- nextMargin && dir.value === 'x' && (extraStyle.marginRight = nextMargin);
219
- nextMargin && dir.value === 'y' && (extraStyle.marginBottom = nextMargin);
216
+ if (index === intLen - 1 && !circular) {
217
+ nextMargin && dir === 'x' && (extraStyle.marginRight = nextMargin);
218
+ nextMargin && dir === 'y' && (extraStyle.marginBottom = nextMargin);
220
219
  }
220
+ // 业务swiper-item自己生成key,内部添加的元素自定义key
221
221
  const newChild = React.cloneElement(child, {
222
222
  itemIndex: index,
223
- customStyle: [itemAnimatedStyles, extraStyle],
224
- key: 'page' + index
223
+ customStyle: extraStyle
225
224
  });
226
225
  return newChild;
227
226
  });
228
227
  const contextValue = {
229
228
  offset,
230
229
  step,
231
- scale: props.scale
230
+ scale: props.scale,
231
+ dir
232
232
  };
233
- return (<SwiperContext.Provider value={contextValue}>{arrChilds}</SwiperContext.Provider>);
233
+ return (<SwiperContext.Provider value={contextValue}>{arrChildren}</SwiperContext.Provider>);
234
234
  }
235
- function createAutoPlay() {
236
- let targetOffset = 0;
237
- let nextIndex = currentIndex.value;
238
- if (!props.circular) {
239
- // 获取下一个位置的坐标, 循环到最后一个元素,直接停止, 取消定时器
240
- if (currentIndex.value === totalElements.value - 1) {
241
- pauseLoop();
235
+ const { loop, pauseLoop, resumeLoop } = useMemo(() => {
236
+ function createAutoPlay() {
237
+ if (!step.value)
242
238
  return;
243
- }
244
- nextIndex += 1;
245
- targetOffset = -nextIndex * step.value - previousMargin;
246
- offset.value = withTiming(targetOffset, {
247
- duration: easeDuration,
248
- easing: easeMap[easeingFunc]
249
- }, () => {
250
- currentIndex.value = nextIndex;
251
- runOnJS(loop)();
252
- });
253
- }
254
- else {
255
- // 默认向右, 向下
256
- if (nextIndex === totalElements.value - 1) {
257
- nextIndex = 0;
258
- targetOffset = -(totalElements.value + patchElementNum) * step.value + previousMargin;
259
- // 执行动画到下一帧
260
- offset.value = withTiming(targetOffset, {
261
- duration: easeDuration
262
- }, () => {
263
- const initOffset = -step.value * patchElementNum + previousMargin;
264
- // 将开始位置设置为真正的位置
265
- offset.value = initOffset;
266
- currentIndex.value = nextIndex;
267
- runOnJS(loop)();
268
- });
269
- }
270
- else {
271
- nextIndex = currentIndex.value + 1;
272
- targetOffset = -(nextIndex + patchElementNum) * step.value + previousMargin;
273
- // 执行动画到下一帧
239
+ let targetOffset = 0;
240
+ let nextIndex = currentIndex.value;
241
+ if (!circularShared.value) {
242
+ // 获取下一个位置的坐标, 循环到最后一个元素,直接停止, 取消定时器
243
+ if (currentIndex.value === childrenLength.value - 1) {
244
+ pauseLoop();
245
+ return;
246
+ }
247
+ nextIndex += 1;
248
+ // targetOffset = -nextIndex * step.value - preMarginShared.value
249
+ targetOffset = -nextIndex * step.value;
274
250
  offset.value = withTiming(targetOffset, {
275
251
  duration: easeDuration,
276
252
  easing: easeMap[easeingFunc]
@@ -279,297 +255,383 @@ const SwiperWrapper = forwardRef((props, ref) => {
279
255
  runOnJS(loop)();
280
256
  });
281
257
  }
258
+ else {
259
+ // 默认向右, 向下
260
+ if (nextIndex === childrenLength.value - 1) {
261
+ nextIndex = 0;
262
+ targetOffset = -(childrenLength.value + patchElmNumShared.value) * step.value + preMarginShared.value;
263
+ // 执行动画到下一帧
264
+ offset.value = withTiming(targetOffset, {
265
+ duration: easeDuration
266
+ }, () => {
267
+ const initOffset = -step.value * patchElmNumShared.value + preMarginShared.value;
268
+ // 将开始位置设置为真正的位置
269
+ offset.value = initOffset;
270
+ currentIndex.value = nextIndex;
271
+ runOnJS(loop)();
272
+ });
273
+ }
274
+ else {
275
+ nextIndex = currentIndex.value + 1;
276
+ targetOffset = -(nextIndex + patchElmNumShared.value) * step.value + preMarginShared.value;
277
+ // 执行动画到下一帧
278
+ offset.value = withTiming(targetOffset, {
279
+ duration: easeDuration,
280
+ easing: easeMap[easeingFunc]
281
+ }, () => {
282
+ currentIndex.value = nextIndex;
283
+ runOnJS(loop)();
284
+ });
285
+ }
286
+ }
282
287
  }
283
- }
288
+ // loop在JS线程中调用,createAutoPlay + useEffect中
289
+ function loop() {
290
+ timerId.current && clearTimeout(timerId.current);
291
+ timerId.current = setTimeout(createAutoPlay, intervalTimer);
292
+ }
293
+ function pauseLoop() {
294
+ timerId.current && clearTimeout(timerId.current);
295
+ }
296
+ // resumeLoop在worklet中调用
297
+ function resumeLoop() {
298
+ if (autoplayShared.value && childrenLength.value > 1) {
299
+ loop();
300
+ }
301
+ }
302
+ return {
303
+ loop,
304
+ pauseLoop,
305
+ resumeLoop
306
+ };
307
+ }, []);
284
308
  function handleSwiperChange(current) {
285
309
  if (props.current !== currentIndex.value) {
286
310
  const eventData = getCustomEvent('change', {}, { detail: { current, source: 'touch' }, layoutRef: layoutRef });
287
311
  props.bindchange && props.bindchange(eventData);
288
312
  }
289
313
  }
290
- function getOffset(index) {
291
- 'worklet';
292
- if (!step.value)
314
+ function getOffset(index, stepValue) {
315
+ if (!stepValue)
293
316
  return 0;
294
317
  let targetOffset = 0;
295
- if (props.circular && totalElements.value > 1) {
296
- const targetIndex = (index || props.current || 0) + patchElementNum;
297
- targetOffset = -(step.value * targetIndex - previousMargin);
318
+ if (circular && children.length > 1) {
319
+ const targetIndex = index + patchElmNum;
320
+ targetOffset = -(stepValue * targetIndex - preMargin);
298
321
  }
299
322
  else {
300
- targetOffset = -(index || props?.current || 0) * step.value;
323
+ targetOffset = -index * stepValue;
301
324
  }
302
325
  return targetOffset;
303
326
  }
304
- function loop() {
305
- timerId.current = setTimeout(() => {
306
- createAutoPlay();
307
- }, intervalTimer);
308
- }
309
- function pauseLoop() {
310
- timerId.current && clearTimeout(timerId.current);
327
+ function updateCurrent(index, stepValue) {
328
+ const targetOffset = getOffset(index || 0, stepValue);
329
+ if (targetOffset !== offset.value) {
330
+ // 内部基于props.current!==currentIndex.value决定是否使用动画及更新currentIndex.value
331
+ if (props.current !== undefined && props.current !== currentIndex.value) {
332
+ offset.value = withTiming(targetOffset, {
333
+ duration: easeDuration,
334
+ easing: easeMap[easeingFunc]
335
+ }, () => {
336
+ currentIndex.value = props.current || 0;
337
+ });
338
+ }
339
+ else {
340
+ offset.value = targetOffset;
341
+ }
342
+ }
311
343
  }
312
- function resumeLoop() {
313
- if (props.autoplay) {
344
+ function updateAutoplay() {
345
+ if (autoplay && children.length > 1) {
314
346
  loop();
315
347
  }
348
+ else {
349
+ pauseLoop();
350
+ }
316
351
  }
352
+ // 1. 用户在当前页切换选中项,动画;用户携带选中index打开到swiper页直接选中不走动画
317
353
  useAnimatedReaction(() => currentIndex.value, (newIndex, preIndex) => {
318
354
  // 这里必须传递函数名, 直接写()=> {}形式会报 访问了未sharedValue信息
319
- const isInit = !preIndex && newIndex === 0;
320
- if (!isInit && newIndex !== preIndex && props.bindchange) {
355
+ if (newIndex !== preIndex && props.bindchange) {
321
356
  runOnJS(handleSwiperChange)(newIndex);
322
357
  }
323
358
  });
324
359
  useEffect(() => {
325
- if (!step.value) {
326
- return;
360
+ let patchStep = 0;
361
+ if (preMargin !== preMarginShared.value) {
362
+ patchStep += preMargin - preMarginShared.value;
327
363
  }
328
- const targetOffset = getOffset();
329
- if (props.current !== undefined && props.current !== currentIndex.value) {
330
- offset.value = withTiming(targetOffset, {
331
- duration: easeDuration,
332
- easing: easeMap[easeingFunc]
333
- }, () => {
334
- currentIndex.value = props.current || 0;
335
- });
364
+ if (nextMargin !== nextMarginShared.value) {
365
+ patchStep += nextMargin - nextMarginShared.value;
336
366
  }
337
- }, [props.current]);
338
- useEffect(() => {
339
- if (!step.value) {
340
- return;
367
+ preMarginShared.value = preMargin;
368
+ nextMarginShared.value = nextMargin;
369
+ const newStep = step.value - patchStep;
370
+ if (step.value !== newStep) {
371
+ step.value = newStep;
372
+ offset.value = getOffset(currentIndex.value, newStep);
341
373
  }
342
- if (props.autoplay) {
343
- resumeLoop();
344
- }
345
- else {
374
+ }, [preMargin, nextMargin]);
375
+ useEffect(() => {
376
+ childrenLength.value = children.length;
377
+ if (children.length - 1 < currentIndex.value) {
346
378
  pauseLoop();
379
+ currentIndex.value = 0;
380
+ offset.value = getOffset(0, step.value);
381
+ if (autoplay && children.length > 1) {
382
+ loop();
383
+ }
347
384
  }
385
+ }, [children.length]);
386
+ useEffect(() => {
387
+ updateCurrent(props.current || 0, step.value);
388
+ }, [props.current]);
389
+ useEffect(() => {
390
+ autoplayShared.value = autoplay;
391
+ updateAutoplay();
348
392
  return () => {
349
- if (props.autoplay) {
393
+ if (autoplay) {
350
394
  pauseLoop();
351
395
  }
352
396
  };
353
- }, [props.autoplay]);
354
- function getTargetPosition(eventData) {
355
- 'worklet';
356
- // 移动的距离
357
- const { translation } = eventData;
358
- let resetOffsetPos = 0;
359
- let selectedIndex = currentIndex.value;
360
- // 是否临界点
361
- let isCriticalItem = false;
362
- // 真实滚动到的偏移量坐标
363
- let moveToTargetPos = 0;
364
- // 当前的位置
365
- const currentOffset = offset.value - previousMargin;
366
- const computedIndex = Math.abs(currentOffset) / step.value;
367
- const moveToIndex = translation < 0 ? Math.ceil(computedIndex) : Math.floor(computedIndex);
368
- // 实际应该定位的索引值
369
- if (!props.circular) {
370
- selectedIndex = moveToIndex;
371
- moveToTargetPos = selectedIndex * step.value;
372
- }
373
- else {
374
- if (moveToIndex >= totalElements.value + patchElementNum) {
375
- selectedIndex = moveToIndex - (totalElements.value + patchElementNum);
376
- resetOffsetPos = (selectedIndex + patchElementNum) * step.value - previousMargin;
377
- moveToTargetPos = moveToIndex * step.value - previousMargin;
378
- isCriticalItem = true;
397
+ }, [autoplay]);
398
+ useEffect(() => {
399
+ if (circular !== circularShared.value) {
400
+ circularShared.value = circular;
401
+ patchElmNumShared.value = circular ? (preMargin ? 2 : 1) : 0;
402
+ offset.value = getOffset(currentIndex.value, step.value);
403
+ }
404
+ }, [circular, preMargin]);
405
+ const { gestureHandler } = useMemo(() => {
406
+ function getTargetPosition(eventData) {
407
+ 'worklet';
408
+ // 移动的距离
409
+ const { translation } = eventData;
410
+ let resetOffsetPos = 0;
411
+ let selectedIndex = currentIndex.value;
412
+ // 是否临界点
413
+ let isCriticalItem = false;
414
+ // 真实滚动到的偏移量坐标
415
+ let moveToTargetPos = 0;
416
+ const tmp = !circularShared.value ? 0 : preMarginShared.value;
417
+ const currentOffset = translation < 0 ? offset.value - tmp : offset.value + tmp;
418
+ const computedIndex = Math.abs(currentOffset) / step.value;
419
+ const moveToIndex = translation < 0 ? Math.ceil(computedIndex) : Math.floor(computedIndex);
420
+ // 实际应该定位的索引值
421
+ if (!circularShared.value) {
422
+ selectedIndex = moveToIndex;
423
+ moveToTargetPos = selectedIndex * step.value;
424
+ }
425
+ else {
426
+ if (moveToIndex >= childrenLength.value + patchElmNumShared.value) {
427
+ selectedIndex = moveToIndex - (childrenLength.value + patchElmNumShared.value);
428
+ resetOffsetPos = (selectedIndex + patchElmNumShared.value) * step.value - preMarginShared.value;
429
+ moveToTargetPos = moveToIndex * step.value - preMarginShared.value;
430
+ isCriticalItem = true;
431
+ }
432
+ else if (moveToIndex <= patchElmNumShared.value - 1) {
433
+ selectedIndex = moveToIndex === 0 ? childrenLength.value - patchElmNumShared.value : childrenLength.value - 1;
434
+ resetOffsetPos = (selectedIndex + patchElmNumShared.value) * step.value - preMarginShared.value;
435
+ moveToTargetPos = moveToIndex * step.value - preMarginShared.value;
436
+ isCriticalItem = true;
437
+ }
438
+ else {
439
+ selectedIndex = moveToIndex - patchElmNumShared.value;
440
+ moveToTargetPos = moveToIndex * step.value - preMarginShared.value;
441
+ }
379
442
  }
380
- else if (moveToIndex <= patchElementNum - 1) {
381
- selectedIndex = moveToIndex === 0 ? totalElements.value - patchElementNum : totalElements.value - 1;
382
- resetOffsetPos = (selectedIndex + patchElementNum) * step.value - previousMargin;
383
- moveToTargetPos = moveToIndex * step.value - previousMargin;
384
- isCriticalItem = true;
443
+ return {
444
+ selectedIndex,
445
+ isCriticalItem,
446
+ resetOffset: -resetOffsetPos,
447
+ targetOffset: -moveToTargetPos
448
+ };
449
+ }
450
+ function canMove(eventData) {
451
+ 'worklet';
452
+ const { translation } = eventData;
453
+ const currentOffset = Math.abs(offset.value);
454
+ if (!circularShared.value) {
455
+ if (translation < 0) {
456
+ return currentOffset < step.value * (childrenLength.value - 1);
457
+ }
458
+ else {
459
+ return currentOffset > 0;
460
+ }
385
461
  }
386
462
  else {
387
- selectedIndex = moveToIndex - patchElementNum;
388
- moveToTargetPos = moveToIndex * step.value - previousMargin;
463
+ return true;
389
464
  }
390
465
  }
391
- return {
392
- selectedIndex,
393
- isCriticalItem,
394
- resetOffset: -resetOffsetPos,
395
- targetOffset: -moveToTargetPos
396
- };
397
- }
398
- function canMove(eventData) {
399
- 'worklet';
400
- const { translation } = eventData;
401
- const currentOffset = Math.abs(offset.value);
402
- if (!props.circular) {
403
- if (translation < 0) {
404
- return currentOffset < step.value * (totalElements.value - 1);
466
+ function handleEnd(eventData) {
467
+ 'worklet';
468
+ const { isCriticalItem, targetOffset, resetOffset, selectedIndex } = getTargetPosition(eventData);
469
+ if (isCriticalItem) {
470
+ offset.value = withTiming(targetOffset, {
471
+ duration: easeDuration,
472
+ easing: easeMap[easeingFunc]
473
+ }, () => {
474
+ if (touchfinish.value !== false) {
475
+ currentIndex.value = selectedIndex;
476
+ offset.value = resetOffset;
477
+ runOnJS(resumeLoop)();
478
+ }
479
+ });
405
480
  }
406
481
  else {
407
- return currentOffset > 0;
482
+ offset.value = withTiming(targetOffset, {
483
+ duration: easeDuration,
484
+ easing: easeMap[easeingFunc]
485
+ }, () => {
486
+ if (touchfinish.value !== false) {
487
+ currentIndex.value = selectedIndex;
488
+ runOnJS(resumeLoop)();
489
+ }
490
+ });
408
491
  }
409
492
  }
410
- else {
411
- return true;
412
- }
413
- }
414
- function handleEnd(eventData) {
415
- 'worklet';
416
- const { isCriticalItem, targetOffset, resetOffset, selectedIndex } = getTargetPosition(eventData);
417
- if (isCriticalItem) {
418
- offset.value = withTiming(targetOffset, {
419
- duration: easeDuration,
420
- easing: easeMap[easeingFunc]
421
- }, () => {
422
- if (touchfinish.value !== false) {
423
- currentIndex.value = selectedIndex;
424
- offset.value = resetOffset;
425
- runOnJS(resumeLoop)();
426
- }
427
- });
428
- }
429
- else {
493
+ function handleBack(eventData) {
494
+ 'worklet';
495
+ const { translation } = eventData;
496
+ // 向右滑动的back:trans < 0, 向左滑动的back: trans < 0
497
+ let currentOffset = Math.abs(offset.value);
498
+ if (circularShared.value) {
499
+ currentOffset += translation < 0 ? preMarginShared.value : -preMarginShared.value;
500
+ }
501
+ const curIndex = currentOffset / step.value;
502
+ const moveToIndex = (translation < 0 ? Math.floor(curIndex) : Math.ceil(curIndex)) - patchElmNumShared.value;
503
+ const targetOffset = -(moveToIndex + patchElmNumShared.value) * step.value + (circularShared.value ? preMarginShared.value : 0);
430
504
  offset.value = withTiming(targetOffset, {
431
505
  duration: easeDuration,
432
506
  easing: easeMap[easeingFunc]
433
507
  }, () => {
434
508
  if (touchfinish.value !== false) {
435
- currentIndex.value = selectedIndex;
509
+ currentIndex.value = moveToIndex;
436
510
  runOnJS(resumeLoop)();
437
511
  }
438
512
  });
439
513
  }
440
- }
441
- function handleBack(eventData) {
442
- 'worklet';
443
- const { translation } = eventData;
444
- // 向右滑动的back:trans < 0, 向左滑动的back: trans < 0
445
- const currentOffset = Math.abs(offset.value);
446
- const curIndex = currentOffset / step.value;
447
- const moveToIndex = (translation < 0 ? Math.floor(curIndex) : Math.ceil(curIndex)) - patchElementNum;
448
- const targetOffset = -(moveToIndex + patchElementNum) * step.value + (translation < 0 ? -previousMargin : previousMargin);
449
- offset.value = withTiming(targetOffset, {
450
- duration: easeDuration,
451
- easing: easeMap[easeingFunc]
452
- }, () => {
453
- if (touchfinish.value !== false) {
454
- currentIndex.value = moveToIndex;
514
+ function handleLongPress() {
515
+ 'worklet';
516
+ const currentOffset = Math.abs(offset.value);
517
+ let preOffset = (currentIndex.value + patchElmNumShared.value) * step.value;
518
+ if (circularShared.value) {
519
+ preOffset -= preMarginShared.value;
520
+ }
521
+ // 正常事件中拿到的transition值(正向滑动<0,倒着滑>0)
522
+ const diffOffset = preOffset - currentOffset;
523
+ const half = Math.abs(diffOffset) > step.value / 2;
524
+ if (+diffOffset === 0) {
455
525
  runOnJS(resumeLoop)();
456
526
  }
457
- });
458
- }
459
- function handleLongPress(eventData) {
460
- 'worklet';
461
- const { translation } = eventData;
462
- const currentOffset = Math.abs(offset.value) + (translation < 0 ? previousMargin : -previousMargin);
463
- const half = currentOffset % step.value > step.value / 2;
464
- // 向右trans < 0, 向左trans > 0
465
- const isExceedHalf = translation < 0 ? half : !half;
466
- if (+translation === 0) {
467
- runOnJS(resumeLoop)();
468
- }
469
- else if (isExceedHalf) {
470
- handleEnd(eventData);
471
- }
472
- else {
473
- handleBack(eventData);
474
- }
475
- }
476
- function reachBoundary(eventData) {
477
- 'worklet';
478
- // 移动的距离
479
- const { translation } = eventData;
480
- const elementsLength = step.value * totalElements.value;
481
- let isBoundary = false;
482
- let resetOffset = 0;
483
- // Y轴向下滚动, transDistance > 0, 向上滚动 < 0 X轴向左滚动, transDistance > 0
484
- const currentOffset = offset.value;
485
- const moveStep = Math.ceil(translation / elementsLength);
486
- if (translation < 0) {
487
- const posEnd = (totalElements.value + patchElementNum + 1) * step.value;
488
- const posReverseEnd = (patchElementNum - 1) * step.value;
489
- if (currentOffset < -posEnd + step.value) {
490
- isBoundary = true;
491
- resetOffset = Math.abs(moveStep) === 0 ? patchElementNum * step.value + translation : moveStep * elementsLength;
527
+ else if (half) {
528
+ handleEnd({ translation: diffOffset });
492
529
  }
493
- if (currentOffset > -posReverseEnd) {
494
- isBoundary = true;
495
- resetOffset = moveStep * elementsLength;
530
+ else {
531
+ handleBack({ translation: diffOffset });
496
532
  }
497
533
  }
498
- else if (translation > 0) {
499
- const posEnd = (patchElementNum - 1) * step.value;
500
- const posReverseEnd = (patchElementNum + totalElements.value) * step.value;
501
- if (currentOffset > -posEnd) {
502
- isBoundary = true;
503
- resetOffset = moveStep * elementsLength + step.value + (moveStep === 1 ? translation : 0);
534
+ function reachBoundary(eventData) {
535
+ 'worklet';
536
+ // 移动的距离
537
+ const { translation } = eventData;
538
+ const elementsLength = step.value * childrenLength.value;
539
+ let isBoundary = false;
540
+ let resetOffset = 0;
541
+ // Y轴向下滚动, transDistance > 0, 向上滚动 < 0 X轴向左滚动, transDistance > 0
542
+ const currentOffset = offset.value;
543
+ const moveStep = Math.ceil(translation / elementsLength);
544
+ if (translation < 0) {
545
+ const posEnd = (childrenLength.value + patchElmNumShared.value + 1) * step.value;
546
+ const posReverseEnd = (patchElmNumShared.value - 1) * step.value;
547
+ if (currentOffset < -posEnd + step.value) {
548
+ isBoundary = true;
549
+ resetOffset = Math.abs(moveStep) === 0 ? patchElmNumShared.value * step.value + translation : moveStep * elementsLength;
550
+ }
551
+ if (currentOffset > -posReverseEnd) {
552
+ isBoundary = true;
553
+ resetOffset = moveStep * elementsLength;
554
+ }
504
555
  }
505
- if (currentOffset < -posReverseEnd) {
506
- isBoundary = true;
507
- resetOffset = moveStep * elementsLength + patchElementNum * step.value;
556
+ else if (translation > 0) {
557
+ const posEnd = (patchElmNumShared.value - 1) * step.value;
558
+ const posReverseEnd = (patchElmNumShared.value + childrenLength.value) * step.value;
559
+ if (currentOffset > -posEnd) {
560
+ isBoundary = true;
561
+ resetOffset = moveStep * elementsLength + step.value + (moveStep === 1 ? translation : 0);
562
+ }
563
+ if (currentOffset < -posReverseEnd) {
564
+ isBoundary = true;
565
+ resetOffset = moveStep * elementsLength + patchElmNumShared.value * step.value;
566
+ }
567
+ }
568
+ return {
569
+ isBoundary,
570
+ resetOffset: -resetOffset
571
+ };
572
+ }
573
+ const gesturePan = Gesture.Pan()
574
+ .onBegin((e) => {
575
+ 'worklet';
576
+ if (!step.value)
577
+ return;
578
+ touchfinish.value = false;
579
+ cancelAnimation(offset);
580
+ runOnJS(pauseLoop)();
581
+ preAbsolutePos.value = e[strAbso];
582
+ moveTranstion.value = e[strAbso];
583
+ moveTime.value = new Date().getTime();
584
+ })
585
+ .onTouchesMove((e) => {
586
+ 'worklet';
587
+ if (touchfinish.value)
588
+ return;
589
+ const touchEventData = e.changedTouches[0];
590
+ const moveDistance = touchEventData[strAbso] - preAbsolutePos.value;
591
+ const eventData = {
592
+ translation: moveDistance
593
+ };
594
+ // 处理用户一直拖拽到临界点的场景, 不会执行onEnd
595
+ if (!circularShared.value && !canMove(eventData)) {
596
+ return;
597
+ }
598
+ const { isBoundary, resetOffset } = reachBoundary(eventData);
599
+ if (isBoundary && circularShared.value) {
600
+ offset.value = resetOffset;
601
+ }
602
+ else {
603
+ offset.value = moveDistance + offset.value;
604
+ }
605
+ preAbsolutePos.value = touchEventData[strAbso];
606
+ })
607
+ .onTouchesUp((e) => {
608
+ 'worklet';
609
+ if (touchfinish.value)
610
+ return;
611
+ const touchEventData = e.changedTouches[0];
612
+ const moveDistance = touchEventData[strAbso] - moveTranstion.value;
613
+ touchfinish.value = true;
614
+ const eventData = {
615
+ translation: moveDistance
616
+ };
617
+ // 用户手指按下起来, 需要计算正确的位置, 比如在滑动过程中突然按下然后起来,需要计算到正确的位置
618
+ if (!circularShared.value && !canMove(eventData)) {
619
+ return;
508
620
  }
509
- }
510
- return {
511
- isBoundary,
512
- resetOffset: -resetOffset
513
- };
514
- }
515
- const gestureHandler = Gesture.Pan()
516
- .onBegin((e) => {
517
- 'worklet';
518
- touchfinish.value = false;
519
- cancelAnimation(offset);
520
- runOnJS(pauseLoop)();
521
- preAbsolutePos.value = e[strAbso];
522
- moveTranstion.value = e[strAbso];
523
- moveTime.value = new Date().getTime();
524
- })
525
- .onTouchesMove((e) => {
526
- 'worklet';
527
- const touchEventData = e.changedTouches[0];
528
- const moveDistance = touchEventData[strAbso] - preAbsolutePos.value;
529
- customTrans.value = moveDistance;
530
- const eventData = {
531
- translation: moveDistance
532
- };
533
- // 处理用户一直拖拽到临界点的场景, 不会执行onEnd
534
- if (!props.circular && !canMove(eventData)) {
535
- return;
536
- }
537
- const { isBoundary, resetOffset } = reachBoundary(eventData);
538
- if (isBoundary && props.circular && !touchfinish.value) {
539
- offset.value = resetOffset;
540
- }
541
- else {
542
- offset.value = moveDistance + offset.value;
543
- }
544
- preAbsolutePos.value = touchEventData[strAbso];
545
- })
546
- .onTouchesUp((e) => {
547
- 'worklet';
548
- const touchEventData = e.changedTouches[0];
549
- const moveDistance = touchEventData[strAbso] - moveTranstion.value;
550
- touchfinish.value = true;
551
- const eventData = {
552
- translation: moveDistance
553
- };
554
- // 用户手指按下起来, 需要计算正确的位置, 比如在滑动过程中突然按下然后起来,需要计算到正确的位置
555
- if (!props.circular && !canMove(eventData)) {
556
- return;
557
- }
558
- if (!moveDistance) {
559
- handleLongPress({ translation: customTrans.value });
560
- }
561
- else {
562
621
  const strVelocity = moveDistance / (new Date().getTime() - moveTime.value) * 1000;
563
622
  if (Math.abs(strVelocity) < longPressRatio) {
564
- handleLongPress(eventData);
623
+ handleLongPress();
565
624
  }
566
625
  else {
567
626
  handleEnd(eventData);
568
627
  }
569
- }
570
- });
628
+ });
629
+ return {
630
+ gestureHandler: gesturePan
631
+ };
632
+ }, []);
571
633
  const animatedStyles = useAnimatedStyle(() => {
572
- if (dir.value === 'x') {
634
+ if (dir === 'x') {
573
635
  return { transform: [{ translateX: offset.value }], opacity: step.value > 0 ? 1 : 0 };
574
636
  }
575
637
  else {
@@ -577,9 +639,10 @@ const SwiperWrapper = forwardRef((props, ref) => {
577
639
  }
578
640
  });
579
641
  function renderSwiper() {
642
+ const arrPages = renderItems();
580
643
  return (<View style={[normalStyle, layoutStyle, styles.swiper]} {...layoutProps} {...innerProps}>
581
644
  <Animated.View style={[{
582
- flexDirection: dir.value === 'x' ? 'row' : 'column',
645
+ flexDirection: dir === 'x' ? 'row' : 'column',
583
646
  width: '100%',
584
647
  height: '100%'
585
648
  }, animatedStyles]}>
@@ -595,7 +658,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
595
658
  {showsPagination && renderPagination()}
596
659
  </View>);
597
660
  }
598
- if (totalElements.value === 1) {
661
+ if (children.length === 1) {
599
662
  return renderSwiper();
600
663
  }
601
664
  else {