@mpxjs/webpack-plugin 2.10.3-beta.17 → 2.10.3-beta.18
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.
- package/lib/runtime/components/react/dist/context.js +5 -1
- package/lib/runtime/components/react/dist/event.config.js +0 -1
- package/lib/runtime/components/react/dist/getInnerListeners.js +148 -149
- package/lib/runtime/components/react/dist/mpx-async-suspense.jsx +145 -0
- package/lib/runtime/components/react/dist/mpx-button.jsx +11 -7
- package/lib/runtime/components/react/dist/mpx-canvas/Image.js +2 -4
- package/lib/runtime/components/react/dist/mpx-canvas/index.jsx +23 -21
- package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +9 -4
- package/lib/runtime/components/react/dist/mpx-checkbox.jsx +9 -5
- package/lib/runtime/components/react/dist/mpx-form.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-icon/icons/cancel.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/clear.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/download.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/info.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/search.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/success.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/success_no_circle.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/waiting.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/icons/warn.png +0 -0
- package/lib/runtime/components/react/dist/mpx-icon/index.jsx +9 -4
- package/lib/runtime/components/react/dist/mpx-image.jsx +92 -41
- package/lib/runtime/components/react/dist/mpx-inline-text.jsx +11 -0
- package/lib/runtime/components/react/dist/mpx-input.jsx +14 -13
- package/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view.jsx +22 -7
- package/lib/runtime/components/react/dist/mpx-label.jsx +9 -5
- package/lib/runtime/components/react/dist/mpx-movable-area.jsx +10 -5
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +206 -80
- package/lib/runtime/components/react/dist/mpx-navigator.jsx +11 -3
- package/lib/runtime/components/react/dist/mpx-picker/date.jsx +194 -68
- package/lib/runtime/components/react/dist/mpx-picker/dateData.js +17 -0
- package/lib/runtime/components/react/dist/mpx-picker/index.jsx +178 -98
- package/lib/runtime/components/react/dist/mpx-picker/multiSelector.jsx +79 -139
- package/lib/runtime/components/react/dist/mpx-picker/region.jsx +190 -90
- package/lib/runtime/components/react/dist/mpx-picker/selector.jsx +60 -75
- package/lib/runtime/components/react/dist/mpx-picker/time.jsx +100 -228
- package/lib/runtime/components/react/dist/{mpx-picker-view.jsx → mpx-picker-view/index.jsx} +16 -15
- package/lib/runtime/components/react/dist/{mpx-picker-view-column.jsx → mpx-picker-view-column/index.jsx} +95 -26
- package/lib/runtime/components/react/dist/{mpx-picker-view-column-item.jsx → mpx-picker-view-column/pickerViewColumnItem.jsx} +16 -16
- package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItemLite.jsx +20 -0
- package/lib/runtime/components/react/dist/{pickerFaces.js → mpx-picker-view-column/pickerViewFaces.js} +6 -0
- package/lib/runtime/components/react/dist/mpx-popup/index.jsx +61 -0
- package/lib/runtime/components/react/dist/mpx-popup/popupBase.jsx +92 -0
- package/lib/runtime/components/react/dist/mpx-portal/index.jsx +5 -1
- package/lib/runtime/components/react/dist/mpx-portal/portal-manager.jsx +3 -5
- package/lib/runtime/components/react/dist/mpx-progress.jsx +163 -0
- package/lib/runtime/components/react/dist/mpx-radio-group.jsx +11 -4
- package/lib/runtime/components/react/dist/mpx-radio.jsx +9 -5
- package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +12 -4
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +317 -89
- package/lib/runtime/components/react/dist/mpx-simple-text.jsx +7 -5
- package/lib/runtime/components/react/dist/mpx-simple-view.jsx +11 -15
- package/lib/runtime/components/react/dist/mpx-slider.jsx +321 -0
- package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +117 -0
- package/lib/runtime/components/react/dist/mpx-sticky-section.jsx +45 -0
- package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +15 -14
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +245 -121
- package/lib/runtime/components/react/dist/mpx-switch.jsx +10 -7
- package/lib/runtime/components/react/dist/mpx-text.jsx +43 -13
- package/lib/runtime/components/react/dist/mpx-video.jsx +12 -7
- package/lib/runtime/components/react/dist/mpx-view.jsx +34 -18
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +40 -35
- package/lib/runtime/components/react/dist/useAnimationHooks.js +35 -90
- package/lib/runtime/components/react/dist/utils.jsx +215 -109
- package/lib/runtime/components/web/mpx-titlebar.vue +21 -18
- package/package.json +1 -1
- /package/lib/runtime/components/react/dist/{pickerVIewContext.js → mpx-picker-view/pickerVIewContext.js} +0 -0
- /package/lib/runtime/components/react/dist/{pickerViewIndicator.jsx → mpx-picker-view-column/pickerViewIndicator.jsx} +0 -0
- /package/lib/runtime/components/react/dist/{pickerViewMask.jsx → mpx-picker-view-column/pickerViewMask.jsx} +0 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { View } from 'react-native';
|
|
2
2
|
import { GestureDetector, Gesture } from 'react-native-gesture-handler';
|
|
3
3
|
import Animated, { useAnimatedStyle, useSharedValue, withTiming, Easing, runOnJS, useAnimatedReaction, cancelAnimation } from 'react-native-reanimated';
|
|
4
|
-
import React, { forwardRef, useRef, useEffect, useMemo } from 'react';
|
|
4
|
+
import React, { forwardRef, useRef, useEffect, useMemo, createElement } from 'react';
|
|
5
5
|
import useInnerProps, { getCustomEvent } from './getInnerListeners';
|
|
6
6
|
import useNodesRef from './useNodesRef'; // 引入辅助函数
|
|
7
|
-
import { useTransformStyle, splitStyle, splitProps, useLayout, wrapChildren } from './utils';
|
|
7
|
+
import { useTransformStyle, splitStyle, splitProps, useLayout, wrapChildren, extendObject, flatGesture, useRunOnJSCallback } from './utils';
|
|
8
8
|
import { SwiperContext } from './context';
|
|
9
|
+
import Portal from './mpx-portal';
|
|
9
10
|
/**
|
|
10
11
|
* 默认的Style类型
|
|
11
12
|
*/
|
|
@@ -70,14 +71,19 @@ const easeMap = {
|
|
|
70
71
|
easeInOutCubic: Easing.inOut(Easing.cubic)
|
|
71
72
|
};
|
|
72
73
|
const SwiperWrapper = forwardRef((props, ref) => {
|
|
73
|
-
const { 'indicator-dots':
|
|
74
|
+
const { 'indicator-dots': showPagination, '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, 'simultaneous-handlers': originSimultaneousHandlers = [], 'wait-for': waitFor = [], style = {}, autoplay = false, circular = false, disableGesture = false, current: propCurrent = 0, bindchange } = props;
|
|
74
75
|
const easeingFunc = props['easing-function'] || 'default';
|
|
75
76
|
const easeDuration = props.duration || 500;
|
|
76
77
|
const horizontal = props.vertical !== undefined ? !props.vertical : true;
|
|
77
78
|
const nodeRef = useRef(null);
|
|
78
|
-
|
|
79
|
+
// 手势协同gesture 1.0
|
|
80
|
+
const swiperGestureRef = useRef();
|
|
81
|
+
useNodesRef(props, ref, nodeRef, {
|
|
82
|
+
// scrollView内部会过滤是否绑定了gestureRef,withRef(swiperGestureRef)给gesture对象设置一个ref(2.0版本)
|
|
83
|
+
gestureRef: swiperGestureRef
|
|
84
|
+
});
|
|
79
85
|
// 计算transfrom之类的
|
|
80
|
-
const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, setWidth, setHeight } = useTransformStyle(style, {
|
|
86
|
+
const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, hasPositionFixed, setWidth, setHeight } = useTransformStyle(style, {
|
|
81
87
|
enableVar,
|
|
82
88
|
externalVarContext,
|
|
83
89
|
parentFontSize,
|
|
@@ -106,27 +112,43 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
106
112
|
// 每个元素的宽度 or 高度,有固定值直接初始化无则0
|
|
107
113
|
const step = useSharedValue(initStep);
|
|
108
114
|
// 记录选中元素的索引值
|
|
109
|
-
const currentIndex = useSharedValue(
|
|
115
|
+
const currentIndex = useSharedValue(propCurrent);
|
|
110
116
|
// const initOffset = getOffset(props.current || 0, initStep)
|
|
111
117
|
// 记录元素的偏移量
|
|
112
|
-
const offset = useSharedValue(getOffset(
|
|
118
|
+
const offset = useSharedValue(getOffset(propCurrent, initStep));
|
|
113
119
|
const strAbso = 'absolute' + dir.toUpperCase();
|
|
120
|
+
const strVelocity = 'velocity' + dir.toUpperCase();
|
|
114
121
|
// 标识手指触摸和抬起, 起点在onBegin
|
|
115
122
|
const touchfinish = useSharedValue(true);
|
|
116
123
|
// 记录上一帧的绝对定位坐标
|
|
117
124
|
const preAbsolutePos = useSharedValue(0);
|
|
118
125
|
// 记录从onBegin 到 onTouchesUp 时移动的距离
|
|
119
126
|
const moveTranstion = useSharedValue(0);
|
|
120
|
-
// 记录从onBegin 到 onTouchesUp 的时间
|
|
121
|
-
const moveTime = useSharedValue(0);
|
|
122
127
|
const timerId = useRef(0);
|
|
123
128
|
const intervalTimer = props.interval || 500;
|
|
129
|
+
const simultaneousHandlers = flatGesture(originSimultaneousHandlers);
|
|
130
|
+
const waitForHandlers = flatGesture(waitFor);
|
|
131
|
+
// 判断gesture手势是否需要协同处理、等待手势失败响应
|
|
132
|
+
const gestureSwitch = useRef(false);
|
|
133
|
+
// 初始化上一次的手势
|
|
134
|
+
const prevSimultaneousHandlersRef = useRef(originSimultaneousHandlers || []);
|
|
135
|
+
const prevWaitForHandlersRef = useRef(waitFor || []);
|
|
136
|
+
const hasSimultaneousHandlersChanged = prevSimultaneousHandlersRef.current.length !== (originSimultaneousHandlers?.length || 0) ||
|
|
137
|
+
(originSimultaneousHandlers || []).some((handler, index) => handler !== prevSimultaneousHandlersRef.current[index]);
|
|
138
|
+
const hasWaitForHandlersChanged = prevWaitForHandlersRef.current.length !== (waitFor?.length || 0) ||
|
|
139
|
+
(waitFor || []).some((handler, index) => handler !== prevWaitForHandlersRef.current[index]);
|
|
140
|
+
if (hasSimultaneousHandlersChanged || hasWaitForHandlersChanged) {
|
|
141
|
+
gestureSwitch.current = !gestureSwitch.current;
|
|
142
|
+
}
|
|
143
|
+
// 存储上一次的手势
|
|
144
|
+
prevSimultaneousHandlersRef.current = originSimultaneousHandlers || [];
|
|
145
|
+
prevWaitForHandlersRef.current = waitFor || [];
|
|
124
146
|
const {
|
|
125
147
|
// 存储layout布局信息
|
|
126
148
|
layoutRef, layoutProps, layoutStyle } = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef, onLayout: onWrapperLayout });
|
|
127
|
-
const innerProps = useInnerProps(props, {
|
|
149
|
+
const innerProps = useInnerProps(extendObject({}, props, {
|
|
128
150
|
ref: nodeRef
|
|
129
|
-
}, [
|
|
151
|
+
}), [
|
|
130
152
|
'style',
|
|
131
153
|
'indicator-dots',
|
|
132
154
|
'indicator-color',
|
|
@@ -148,7 +170,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
148
170
|
const iStep = dir === 'x' ? realWidth : realHeight;
|
|
149
171
|
if (iStep !== step.value) {
|
|
150
172
|
step.value = iStep;
|
|
151
|
-
updateCurrent(
|
|
173
|
+
updateCurrent(propCurrent, iStep);
|
|
152
174
|
updateAutoplay();
|
|
153
175
|
}
|
|
154
176
|
}
|
|
@@ -164,8 +186,6 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
164
186
|
}
|
|
165
187
|
});
|
|
166
188
|
function renderPagination() {
|
|
167
|
-
if (children.length <= 1)
|
|
168
|
-
return null;
|
|
169
189
|
const activeColor = activeDotColor || '#007aff';
|
|
170
190
|
const unActionColor = dotColor || 'rgba(0,0,0,.2)';
|
|
171
191
|
// 正常渲染所有dots
|
|
@@ -187,8 +207,8 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
187
207
|
dotAnimatedStyle
|
|
188
208
|
]}/>
|
|
189
209
|
{dots}
|
|
190
|
-
|
|
191
|
-
|
|
210
|
+
</View>
|
|
211
|
+
</View>);
|
|
192
212
|
}
|
|
193
213
|
function renderItems() {
|
|
194
214
|
const intLen = children.length;
|
|
@@ -252,7 +272,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
252
272
|
easing: easeMap[easeingFunc]
|
|
253
273
|
}, () => {
|
|
254
274
|
currentIndex.value = nextIndex;
|
|
255
|
-
runOnJS(
|
|
275
|
+
runOnJS(runOnJSCallback)('loop');
|
|
256
276
|
});
|
|
257
277
|
}
|
|
258
278
|
else {
|
|
@@ -268,7 +288,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
268
288
|
// 将开始位置设置为真正的位置
|
|
269
289
|
offset.value = initOffset;
|
|
270
290
|
currentIndex.value = nextIndex;
|
|
271
|
-
runOnJS(
|
|
291
|
+
runOnJS(runOnJSCallback)('loop');
|
|
272
292
|
});
|
|
273
293
|
}
|
|
274
294
|
else {
|
|
@@ -280,7 +300,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
280
300
|
easing: easeMap[easeingFunc]
|
|
281
301
|
}, () => {
|
|
282
302
|
currentIndex.value = nextIndex;
|
|
283
|
-
runOnJS(
|
|
303
|
+
runOnJS(runOnJSCallback)('loop');
|
|
284
304
|
});
|
|
285
305
|
}
|
|
286
306
|
}
|
|
@@ -305,12 +325,19 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
305
325
|
resumeLoop
|
|
306
326
|
};
|
|
307
327
|
}, []);
|
|
308
|
-
function handleSwiperChange(current) {
|
|
309
|
-
if (
|
|
328
|
+
function handleSwiperChange(current, pCurrent) {
|
|
329
|
+
if (pCurrent !== currentIndex.value) {
|
|
310
330
|
const eventData = getCustomEvent('change', {}, { detail: { current, source: 'touch' }, layoutRef: layoutRef });
|
|
311
|
-
|
|
331
|
+
bindchange && bindchange(eventData);
|
|
312
332
|
}
|
|
313
333
|
}
|
|
334
|
+
const runOnJSCallbackRef = useRef({
|
|
335
|
+
loop,
|
|
336
|
+
pauseLoop,
|
|
337
|
+
resumeLoop,
|
|
338
|
+
handleSwiperChange
|
|
339
|
+
});
|
|
340
|
+
const runOnJSCallback = useRunOnJSCallback(runOnJSCallbackRef);
|
|
314
341
|
function getOffset(index, stepValue) {
|
|
315
342
|
if (!stepValue)
|
|
316
343
|
return 0;
|
|
@@ -328,12 +355,12 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
328
355
|
const targetOffset = getOffset(index || 0, stepValue);
|
|
329
356
|
if (targetOffset !== offset.value) {
|
|
330
357
|
// 内部基于props.current!==currentIndex.value决定是否使用动画及更新currentIndex.value
|
|
331
|
-
if (
|
|
358
|
+
if (propCurrent !== undefined && propCurrent !== currentIndex.value) {
|
|
332
359
|
offset.value = withTiming(targetOffset, {
|
|
333
360
|
duration: easeDuration,
|
|
334
361
|
easing: easeMap[easeingFunc]
|
|
335
362
|
}, () => {
|
|
336
|
-
currentIndex.value =
|
|
363
|
+
currentIndex.value = propCurrent;
|
|
337
364
|
});
|
|
338
365
|
}
|
|
339
366
|
else {
|
|
@@ -352,8 +379,8 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
352
379
|
// 1. 用户在当前页切换选中项,动画;用户携带选中index打开到swiper页直接选中不走动画
|
|
353
380
|
useAnimatedReaction(() => currentIndex.value, (newIndex, preIndex) => {
|
|
354
381
|
// 这里必须传递函数名, 直接写()=> {}形式会报 访问了未sharedValue信息
|
|
355
|
-
if (newIndex !== preIndex &&
|
|
356
|
-
runOnJS(
|
|
382
|
+
if (newIndex !== preIndex && bindchange) {
|
|
383
|
+
runOnJS(runOnJSCallback)('handleSwiperChange', newIndex, propCurrent);
|
|
357
384
|
}
|
|
358
385
|
});
|
|
359
386
|
useEffect(() => {
|
|
@@ -384,8 +411,12 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
384
411
|
}
|
|
385
412
|
}, [children.length]);
|
|
386
413
|
useEffect(() => {
|
|
387
|
-
|
|
388
|
-
|
|
414
|
+
// 1. 如果用户在touch的过程中, 外部更新了current以外部为准(小程序表现)
|
|
415
|
+
// 2. 手指滑动过程中更新索引,外部会把current再传入进来,导致offset直接更新,增加判断不同才更新
|
|
416
|
+
if (propCurrent !== currentIndex.value) {
|
|
417
|
+
updateCurrent(propCurrent, step.value);
|
|
418
|
+
}
|
|
419
|
+
}, [propCurrent]);
|
|
389
420
|
useEffect(() => {
|
|
390
421
|
autoplayShared.value = autoplay;
|
|
391
422
|
updateAutoplay();
|
|
@@ -406,7 +437,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
406
437
|
function getTargetPosition(eventData) {
|
|
407
438
|
'worklet';
|
|
408
439
|
// 移动的距离
|
|
409
|
-
const {
|
|
440
|
+
const { transdir } = eventData;
|
|
410
441
|
let resetOffsetPos = 0;
|
|
411
442
|
let selectedIndex = currentIndex.value;
|
|
412
443
|
// 是否临界点
|
|
@@ -414,9 +445,9 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
414
445
|
// 真实滚动到的偏移量坐标
|
|
415
446
|
let moveToTargetPos = 0;
|
|
416
447
|
const tmp = !circularShared.value ? 0 : preMarginShared.value;
|
|
417
|
-
const currentOffset =
|
|
448
|
+
const currentOffset = transdir < 0 ? offset.value - tmp : offset.value + tmp;
|
|
418
449
|
const computedIndex = Math.abs(currentOffset) / step.value;
|
|
419
|
-
const moveToIndex =
|
|
450
|
+
const moveToIndex = transdir < 0 ? Math.ceil(computedIndex) : Math.floor(computedIndex);
|
|
420
451
|
// 实际应该定位的索引值
|
|
421
452
|
if (!circularShared.value) {
|
|
422
453
|
selectedIndex = moveToIndex;
|
|
@@ -449,14 +480,18 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
449
480
|
}
|
|
450
481
|
function canMove(eventData) {
|
|
451
482
|
'worklet';
|
|
452
|
-
|
|
453
|
-
|
|
483
|
+
// 旧版:如果在快速多次滑动时,只根据当前的offset判断,会出现offset没超出,加上translation后越界的场景(如在倒数第二个元素快速滑动)
|
|
484
|
+
// 新版:会加上translation
|
|
485
|
+
const { translation, transdir } = eventData;
|
|
486
|
+
const gestureMovePos = offset.value + translation;
|
|
454
487
|
if (!circularShared.value) {
|
|
455
|
-
|
|
456
|
-
|
|
488
|
+
// 如果只判断区间,中间非滑动状态(handleResistanceMove)向左滑动,突然改为向右滑动,但是还在非滑动态,本应该可滑动判断为了不可滑动
|
|
489
|
+
const posEnd = -step.value * (childrenLength.value - 1);
|
|
490
|
+
if (transdir < 0) {
|
|
491
|
+
return gestureMovePos > posEnd;
|
|
457
492
|
}
|
|
458
493
|
else {
|
|
459
|
-
return
|
|
494
|
+
return gestureMovePos < 0;
|
|
460
495
|
}
|
|
461
496
|
}
|
|
462
497
|
else {
|
|
@@ -474,7 +509,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
474
509
|
if (touchfinish.value !== false) {
|
|
475
510
|
currentIndex.value = selectedIndex;
|
|
476
511
|
offset.value = resetOffset;
|
|
477
|
-
runOnJS(
|
|
512
|
+
runOnJS(runOnJSCallback)('resumeLoop');
|
|
478
513
|
}
|
|
479
514
|
});
|
|
480
515
|
}
|
|
@@ -485,21 +520,21 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
485
520
|
}, () => {
|
|
486
521
|
if (touchfinish.value !== false) {
|
|
487
522
|
currentIndex.value = selectedIndex;
|
|
488
|
-
runOnJS(
|
|
523
|
+
runOnJS(runOnJSCallback)('resumeLoop');
|
|
489
524
|
}
|
|
490
525
|
});
|
|
491
526
|
}
|
|
492
527
|
}
|
|
493
528
|
function handleBack(eventData) {
|
|
494
529
|
'worklet';
|
|
495
|
-
const {
|
|
530
|
+
const { transdir } = eventData;
|
|
496
531
|
// 向右滑动的back:trans < 0, 向左滑动的back: trans < 0
|
|
497
532
|
let currentOffset = Math.abs(offset.value);
|
|
498
533
|
if (circularShared.value) {
|
|
499
|
-
currentOffset +=
|
|
534
|
+
currentOffset += transdir < 0 ? preMarginShared.value : -preMarginShared.value;
|
|
500
535
|
}
|
|
501
536
|
const curIndex = currentOffset / step.value;
|
|
502
|
-
const moveToIndex = (
|
|
537
|
+
const moveToIndex = (transdir < 0 ? Math.floor(curIndex) : Math.ceil(curIndex)) - patchElmNumShared.value;
|
|
503
538
|
const targetOffset = -(moveToIndex + patchElmNumShared.value) * step.value + (circularShared.value ? preMarginShared.value : 0);
|
|
504
539
|
offset.value = withTiming(targetOffset, {
|
|
505
540
|
duration: easeDuration,
|
|
@@ -507,69 +542,106 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
507
542
|
}, () => {
|
|
508
543
|
if (touchfinish.value !== false) {
|
|
509
544
|
currentIndex.value = moveToIndex;
|
|
510
|
-
runOnJS(
|
|
545
|
+
runOnJS(runOnJSCallback)('resumeLoop');
|
|
511
546
|
}
|
|
512
547
|
});
|
|
513
548
|
}
|
|
514
|
-
|
|
549
|
+
// 当前的offset和index多对应的offset进行对比,判断是否超过一半
|
|
550
|
+
function computeHalf(eventData) {
|
|
515
551
|
'worklet';
|
|
552
|
+
const { transdir } = eventData;
|
|
516
553
|
const currentOffset = Math.abs(offset.value);
|
|
517
554
|
let preOffset = (currentIndex.value + patchElmNumShared.value) * step.value;
|
|
518
555
|
if (circularShared.value) {
|
|
519
556
|
preOffset -= preMarginShared.value;
|
|
520
557
|
}
|
|
521
|
-
// 正常事件中拿到的
|
|
558
|
+
// 正常事件中拿到的translation值(正向滑动<0,倒着滑>0)
|
|
522
559
|
const diffOffset = preOffset - currentOffset;
|
|
523
560
|
const half = Math.abs(diffOffset) > step.value / 2;
|
|
561
|
+
const isTriggerUpdateHalf = (transdir < 0 && currentOffset < preOffset) || (transdir > 0 && currentOffset > preOffset);
|
|
562
|
+
return {
|
|
563
|
+
diffOffset,
|
|
564
|
+
half,
|
|
565
|
+
isTriggerUpdateHalf
|
|
566
|
+
};
|
|
567
|
+
}
|
|
568
|
+
function handleLongPress(eventData) {
|
|
569
|
+
'worklet';
|
|
570
|
+
const { diffOffset, half, isTriggerUpdateHalf } = computeHalf(eventData);
|
|
524
571
|
if (+diffOffset === 0) {
|
|
525
|
-
runOnJS(
|
|
572
|
+
runOnJS(runOnJSCallback)('resumeLoop');
|
|
573
|
+
}
|
|
574
|
+
else if (isTriggerUpdateHalf) {
|
|
575
|
+
// 如果触发了onUpdate时的索引变更
|
|
576
|
+
handleEnd(eventData);
|
|
526
577
|
}
|
|
527
578
|
else if (half) {
|
|
528
|
-
handleEnd(
|
|
579
|
+
handleEnd(eventData);
|
|
529
580
|
}
|
|
530
581
|
else {
|
|
531
|
-
handleBack(
|
|
582
|
+
handleBack(eventData);
|
|
532
583
|
}
|
|
533
584
|
}
|
|
534
585
|
function reachBoundary(eventData) {
|
|
535
586
|
'worklet';
|
|
536
|
-
//
|
|
587
|
+
// 1. 基于当前的offset和translation判断是否超过当前边界值
|
|
537
588
|
const { translation } = eventData;
|
|
538
|
-
const
|
|
589
|
+
const boundaryStart = -patchElmNumShared.value * step.value;
|
|
590
|
+
const boundaryEnd = -(childrenLength.value + patchElmNumShared.value) * step.value;
|
|
591
|
+
const moveToOffset = offset.value + translation;
|
|
539
592
|
let isBoundary = false;
|
|
540
593
|
let resetOffset = 0;
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
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
|
-
}
|
|
594
|
+
if (moveToOffset < boundaryEnd) {
|
|
595
|
+
isBoundary = true;
|
|
596
|
+
// 超过边界的距离
|
|
597
|
+
const exceedLength = Math.abs(moveToOffset) - Math.abs(boundaryEnd);
|
|
598
|
+
// 计算对标正常元素所在的offset
|
|
599
|
+
resetOffset = patchElmNumShared.value * step.value + exceedLength;
|
|
555
600
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
}
|
|
563
|
-
if (currentOffset < -posReverseEnd) {
|
|
564
|
-
isBoundary = true;
|
|
565
|
-
resetOffset = moveStep * elementsLength + patchElmNumShared.value * step.value;
|
|
566
|
-
}
|
|
601
|
+
if (moveToOffset > boundaryStart) {
|
|
602
|
+
isBoundary = true;
|
|
603
|
+
// 超过边界的距离
|
|
604
|
+
const exceedLength = Math.abs(boundaryStart) - Math.abs(moveToOffset);
|
|
605
|
+
// 计算对标正常元素所在的offset
|
|
606
|
+
resetOffset = (patchElmNumShared.value + childrenLength.value - 1) * step.value + (step.value - exceedLength);
|
|
567
607
|
}
|
|
568
608
|
return {
|
|
569
609
|
isBoundary,
|
|
570
610
|
resetOffset: -resetOffset
|
|
571
611
|
};
|
|
572
612
|
}
|
|
613
|
+
// 非循环超出边界,应用阻力; 开始滑动少阻力小,滑动越长阻力越大
|
|
614
|
+
function handleResistanceMove(eventData) {
|
|
615
|
+
'worklet';
|
|
616
|
+
const { translation, transdir } = eventData;
|
|
617
|
+
const moveToOffset = offset.value + translation;
|
|
618
|
+
const maxOverDrag = Math.floor(step.value / 2);
|
|
619
|
+
const maxOffset = translation < 0 ? -(childrenLength.value - 1) * step.value : 0;
|
|
620
|
+
let resistance = 0.1;
|
|
621
|
+
let overDrag = 0;
|
|
622
|
+
let finalOffset = 0;
|
|
623
|
+
// 向右向下小于0, 向左向上大于0;
|
|
624
|
+
if (transdir < 0) {
|
|
625
|
+
overDrag = Math.abs(moveToOffset - maxOffset);
|
|
626
|
+
}
|
|
627
|
+
else {
|
|
628
|
+
overDrag = Math.abs(moveToOffset);
|
|
629
|
+
}
|
|
630
|
+
// 滑动越多resistance越小
|
|
631
|
+
resistance = 1 - overDrag / maxOverDrag;
|
|
632
|
+
// 确保阻力在合理范围内
|
|
633
|
+
resistance = Math.min(0.5, resistance);
|
|
634
|
+
// 限制在最大拖拽范围内
|
|
635
|
+
if (transdir < 0) {
|
|
636
|
+
const adjustOffset = offset.value + translation * resistance;
|
|
637
|
+
finalOffset = Math.max(adjustOffset, maxOffset - maxOverDrag);
|
|
638
|
+
}
|
|
639
|
+
else {
|
|
640
|
+
const adjustOffset = offset.value + translation * resistance;
|
|
641
|
+
finalOffset = Math.min(adjustOffset, maxOverDrag);
|
|
642
|
+
}
|
|
643
|
+
return finalOffset;
|
|
644
|
+
}
|
|
573
645
|
const gesturePan = Gesture.Pan()
|
|
574
646
|
.onBegin((e) => {
|
|
575
647
|
'worklet';
|
|
@@ -577,59 +649,113 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
577
649
|
return;
|
|
578
650
|
touchfinish.value = false;
|
|
579
651
|
cancelAnimation(offset);
|
|
580
|
-
runOnJS(
|
|
652
|
+
runOnJS(runOnJSCallback)('pauseLoop');
|
|
581
653
|
preAbsolutePos.value = e[strAbso];
|
|
582
654
|
moveTranstion.value = e[strAbso];
|
|
583
|
-
moveTime.value = new Date().getTime();
|
|
584
655
|
})
|
|
585
|
-
.
|
|
656
|
+
.onUpdate((e) => {
|
|
586
657
|
'worklet';
|
|
587
|
-
|
|
658
|
+
const moveDistance = e[strAbso] - preAbsolutePos.value;
|
|
659
|
+
if (touchfinish.value || moveDistance === 0)
|
|
588
660
|
return;
|
|
589
|
-
const touchEventData = e.changedTouches[0];
|
|
590
|
-
const moveDistance = touchEventData[strAbso] - preAbsolutePos.value;
|
|
591
661
|
const eventData = {
|
|
592
|
-
translation: moveDistance
|
|
662
|
+
translation: moveDistance,
|
|
663
|
+
transdir: moveDistance
|
|
593
664
|
};
|
|
594
|
-
//
|
|
595
|
-
|
|
665
|
+
// 1. 支持滑动中超出一半更新索引的能力:只更新索引并不会影响onFinalize依据当前offset计算的索引
|
|
666
|
+
const { half } = computeHalf(eventData);
|
|
667
|
+
if (childrenLength.value > 1 && half) {
|
|
668
|
+
const { selectedIndex } = getTargetPosition(eventData);
|
|
669
|
+
currentIndex.value = selectedIndex;
|
|
670
|
+
}
|
|
671
|
+
// 2. 非循环: 处理用户一直拖拽到临界点的场景,如果放到onFinalize无法阻止offset.value更新为越界的值
|
|
672
|
+
if (!circularShared.value) {
|
|
673
|
+
if (canMove(eventData)) {
|
|
674
|
+
offset.value = moveDistance + offset.value;
|
|
675
|
+
}
|
|
676
|
+
else {
|
|
677
|
+
const finalOffset = handleResistanceMove(eventData);
|
|
678
|
+
offset.value = finalOffset;
|
|
679
|
+
}
|
|
680
|
+
preAbsolutePos.value = e[strAbso];
|
|
596
681
|
return;
|
|
597
682
|
}
|
|
683
|
+
// 3. 循环更新: 只有一个元素时可滑动,加入阻力
|
|
684
|
+
if (circularShared.value && childrenLength.value === 1) {
|
|
685
|
+
const finalOffset = handleResistanceMove(eventData);
|
|
686
|
+
offset.value = finalOffset;
|
|
687
|
+
preAbsolutePos.value = e[strAbso];
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
// 4. 循环更新:正常
|
|
598
691
|
const { isBoundary, resetOffset } = reachBoundary(eventData);
|
|
599
|
-
if (isBoundary && circularShared.value) {
|
|
692
|
+
if (childrenLength.value > 1 && isBoundary && circularShared.value) {
|
|
600
693
|
offset.value = resetOffset;
|
|
601
694
|
}
|
|
602
695
|
else {
|
|
603
696
|
offset.value = moveDistance + offset.value;
|
|
604
697
|
}
|
|
605
|
-
preAbsolutePos.value =
|
|
698
|
+
preAbsolutePos.value = e[strAbso];
|
|
606
699
|
})
|
|
607
|
-
.
|
|
700
|
+
.onFinalize((e) => {
|
|
608
701
|
'worklet';
|
|
609
702
|
if (touchfinish.value)
|
|
610
703
|
return;
|
|
611
|
-
const touchEventData = e.changedTouches[0];
|
|
612
|
-
const moveDistance = touchEventData[strAbso] - moveTranstion.value;
|
|
613
704
|
touchfinish.value = true;
|
|
705
|
+
// 触发过onUpdate正常情况下e[strAbso] - preAbsolutePos.value=0; 未触发过onUpdate的情况下e[strAbso] - preAbsolutePos.value 不为0
|
|
706
|
+
const moveDistance = e[strAbso] - preAbsolutePos.value;
|
|
614
707
|
const eventData = {
|
|
615
|
-
translation: moveDistance
|
|
708
|
+
translation: moveDistance,
|
|
709
|
+
transdir: moveDistance !== 0 ? moveDistance : e[strAbso] - moveTranstion.value
|
|
616
710
|
};
|
|
617
|
-
//
|
|
711
|
+
// 1. 只有一个元素:循环 和 非循环状态,都走回弹效果
|
|
712
|
+
if (childrenLength.value === 1) {
|
|
713
|
+
offset.value = withTiming(0, {
|
|
714
|
+
duration: easeDuration,
|
|
715
|
+
easing: easeMap[easeingFunc]
|
|
716
|
+
});
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
// 2.非循环状态不可移动态:最后一个元素 和 第一个元素
|
|
720
|
+
// 非循环支持最后元素可滑动能力后,向左快速移动未超过最大可移动范围一半,因为offset为正值,向左滑动handleBack,默认向上取整
|
|
721
|
+
// 但是在offset大于0时,取0。[-100, 0](back取0), [0, 100](back取1), 所以handleLongPress里的处理逻辑需要兼容支持,因此这里直接单独处理,不耦合下方公共的判断逻辑。
|
|
618
722
|
if (!circularShared.value && !canMove(eventData)) {
|
|
723
|
+
if (eventData.transdir < 0) {
|
|
724
|
+
handleBack(eventData);
|
|
725
|
+
}
|
|
726
|
+
else {
|
|
727
|
+
handleEnd(eventData);
|
|
728
|
+
}
|
|
619
729
|
return;
|
|
620
730
|
}
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
731
|
+
// 3. 非循环状态可移动态、循环状态, 正常逻辑处理
|
|
732
|
+
const velocity = e[strVelocity];
|
|
733
|
+
if (Math.abs(velocity) < longPressRatio) {
|
|
734
|
+
handleLongPress(eventData);
|
|
624
735
|
}
|
|
625
736
|
else {
|
|
626
737
|
handleEnd(eventData);
|
|
627
738
|
}
|
|
628
|
-
})
|
|
739
|
+
})
|
|
740
|
+
.withRef(swiperGestureRef);
|
|
741
|
+
// swiper横向,当y轴滑动5像素手势失效;swiper纵向只响应swiper的滑动事件
|
|
742
|
+
if (dir === 'x') {
|
|
743
|
+
gesturePan.activeOffsetX([-2, 2]).failOffsetY([-5, 5]);
|
|
744
|
+
}
|
|
745
|
+
else {
|
|
746
|
+
gesturePan.activeOffsetY([-2, 2]).failOffsetX([-5, 5]);
|
|
747
|
+
}
|
|
748
|
+
// 手势协同2.0
|
|
749
|
+
if (simultaneousHandlers && simultaneousHandlers.length) {
|
|
750
|
+
gesturePan.simultaneousWithExternalGesture(...simultaneousHandlers);
|
|
751
|
+
}
|
|
752
|
+
if (waitForHandlers && waitForHandlers.length) {
|
|
753
|
+
gesturePan.requireExternalGestureToFail(...waitForHandlers);
|
|
754
|
+
}
|
|
629
755
|
return {
|
|
630
756
|
gestureHandler: gesturePan
|
|
631
757
|
};
|
|
632
|
-
}, []);
|
|
758
|
+
}, [gestureSwitch.current]);
|
|
633
759
|
const animatedStyles = useAnimatedStyle(() => {
|
|
634
760
|
if (dir === 'x') {
|
|
635
761
|
return { transform: [{ translateX: offset.value }], opacity: step.value > 0 ? 1 : 0 };
|
|
@@ -638,34 +764,32 @@ const SwiperWrapper = forwardRef((props, ref) => {
|
|
|
638
764
|
return { transform: [{ translateY: offset.value }], opacity: step.value > 0 ? 1 : 0 };
|
|
639
765
|
}
|
|
640
766
|
});
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
return renderSwiper();
|
|
767
|
+
let finalComponent;
|
|
768
|
+
const arrPages = renderItems();
|
|
769
|
+
const mergeProps = Object.assign({
|
|
770
|
+
style: [normalStyle, layoutStyle, styles.swiper]
|
|
771
|
+
}, layoutProps, innerProps);
|
|
772
|
+
const animateComponent = createElement(Animated.View, {
|
|
773
|
+
style: [{ flexDirection: dir === 'x' ? 'row' : 'column', width: '100%', height: '100%' }, animatedStyles]
|
|
774
|
+
}, wrapChildren({
|
|
775
|
+
children: arrPages
|
|
776
|
+
}, {
|
|
777
|
+
hasVarDec,
|
|
778
|
+
varContext: varContextRef.current,
|
|
779
|
+
textStyle,
|
|
780
|
+
textProps
|
|
781
|
+
}));
|
|
782
|
+
const renderChildrens = showPagination ? [animateComponent, renderPagination()] : animateComponent;
|
|
783
|
+
finalComponent = createElement(View, mergeProps, renderChildrens);
|
|
784
|
+
if (!disableGesture) {
|
|
785
|
+
finalComponent = createElement(GestureDetector, {
|
|
786
|
+
gesture: gestureHandler
|
|
787
|
+
}, finalComponent);
|
|
663
788
|
}
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
{renderSwiper()}
|
|
667
|
-
</GestureDetector>);
|
|
789
|
+
if (hasPositionFixed) {
|
|
790
|
+
finalComponent = createElement(Portal, null, finalComponent);
|
|
668
791
|
}
|
|
792
|
+
return finalComponent;
|
|
669
793
|
});
|
|
670
794
|
SwiperWrapper.displayName = 'MpxSwiperWrapper';
|
|
671
795
|
export default SwiperWrapper;
|