@mpxjs/webpack-plugin 2.10.13 → 2.10.14-beta.2

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/index.js CHANGED
@@ -199,6 +199,7 @@ class MpxWebpackPlugin {
199
199
  }, options.nativeConfig)
200
200
  options.webConfig = options.webConfig || {}
201
201
  options.rnConfig = options.rnConfig || {}
202
+ options.rnConfig.supportSubpackage = options.rnConfig.supportSubpackage !== undefined ? options.rnConfig.supportSubpackage : true
202
203
  options.partialCompileRules = options.partialCompileRules || null
203
204
  options.asyncSubpackageRules = options.asyncSubpackageRules || []
204
205
  options.optimizeRenderRules = options.optimizeRenderRules ? (Array.isArray(options.optimizeRenderRules) ? options.optimizeRenderRules : [options.optimizeRenderRules]) : []
@@ -783,7 +784,7 @@ class MpxWebpackPlugin {
783
784
  removedChunks: [],
784
785
  forceProxyEventRules: this.options.forceProxyEventRules,
785
786
  // 若配置disableRequireAsync=true, 则全平台构建不支持异步分包
786
- supportRequireAsync: !this.options.disableRequireAsync && (this.options.mode === 'wx' || this.options.mode === 'ali' || this.options.mode === 'tt' || isWeb(this.options.mode) || isReact(this.options.mode)),
787
+ supportRequireAsync: !this.options.disableRequireAsync && (this.options.mode === 'wx' || this.options.mode === 'ali' || this.options.mode === 'tt' || isWeb(this.options.mode) || (isReact(this.options.mode) && this.options.rnConfig.supportSubpackage)),
787
788
  partialCompileRules: this.options.partialCompileRules,
788
789
  collectDynamicEntryInfo: ({ resource, packageName, filename, entryType, hasAsync }) => {
789
790
  const curInfo = mpx.dynamicEntryInfo[packageName] = mpx.dynamicEntryInfo[packageName] || {
@@ -46,7 +46,8 @@ import { getComponent, getAsyncSuspense } from ${stringifyRequest(loaderContext,
46
46
  const componentsMap = buildComponentsMap({
47
47
  localComponentsMap,
48
48
  loaderContext,
49
- jsonConfig
49
+ jsonConfig,
50
+ rnConfig
50
51
  })
51
52
  output += buildGlobalParams({ moduleId, scriptSrcMode, loaderContext, isProduction, ctorType, jsonConfig, componentsMap, pagesMap, firstPage, hasApp })
52
53
  output += getRequireScript({ ctorType, script, loaderContext })
@@ -58,7 +59,8 @@ import { getComponent, getAsyncSuspense } from ${stringifyRequest(loaderContext,
58
59
  localComponentsMap,
59
60
  builtInComponentsMap,
60
61
  loaderContext,
61
- jsonConfig
62
+ jsonConfig,
63
+ rnConfig
62
64
  })
63
65
 
64
66
  output += buildGlobalParams({ moduleId, scriptSrcMode, loaderContext, isProduction, ctorType, jsonConfig, componentsMap, outputPath, genericsInfo, componentGenerics, hasApp })
@@ -59,7 +59,7 @@ function buildPagesMap ({ localPagesMap, loaderContext, jsonConfig, rnConfig })
59
59
  Object.keys(localPagesMap).forEach((pagePath) => {
60
60
  const pageCfg = localPagesMap[pagePath]
61
61
  const pageRequest = stringifyRequest(loaderContext, pageCfg.resource)
62
- if (pageCfg.async) {
62
+ if (pageCfg.async && rnConfig.supportSubpackage) {
63
63
  const moduleId = mpx.getModuleId(pageCfg.resource)
64
64
  const getFallback = rnConfig.asyncChunk && rnConfig.asyncChunk.fallback && getComponentGetter(getComponent(stringifyRequest(loaderContext, addQuery(rnConfig.asyncChunk.fallback, { isComponent: true })), 'PageFallback'))
65
65
  const getLoading = rnConfig.asyncChunk && rnConfig.asyncChunk.loading && getComponentGetter(getComponent(stringifyRequest(loaderContext, addQuery(rnConfig.asyncChunk.loading, { isComponent: true })), 'PageLoading'))
@@ -81,14 +81,14 @@ function buildPagesMap ({ localPagesMap, loaderContext, jsonConfig, rnConfig })
81
81
  }
82
82
  }
83
83
 
84
- function buildComponentsMap ({ localComponentsMap, builtInComponentsMap, loaderContext, jsonConfig }) {
84
+ function buildComponentsMap ({ localComponentsMap, builtInComponentsMap, loaderContext, jsonConfig, rnConfig }) {
85
85
  const componentsMap = {}
86
86
  const mpx = loaderContext.getMpx()
87
87
  if (localComponentsMap) {
88
88
  Object.keys(localComponentsMap).forEach((componentName) => {
89
89
  const componentCfg = localComponentsMap[componentName]
90
90
  const componentRequest = stringifyRequest(loaderContext, componentCfg.resource)
91
- if (componentCfg.async) {
91
+ if (componentCfg.async && rnConfig.supportSubpackage) {
92
92
  const moduleId = mpx.getModuleId(componentCfg.resource)
93
93
  const placeholder = jsonConfig.componentPlaceholder && jsonConfig.componentPlaceholder[componentName]
94
94
  let getFallback
@@ -22,7 +22,7 @@ import { StyleSheet } from 'react-native';
22
22
  import useInnerProps, { getCustomEvent } from './getInnerListeners';
23
23
  import useNodesRef from './useNodesRef';
24
24
  import { MovableAreaContext } from './context';
25
- import { useTransformStyle, splitProps, splitStyle, HIDDEN_STYLE, wrapChildren, flatGesture, extendObject, omit, useNavigation } from './utils';
25
+ import { useTransformStyle, splitProps, splitStyle, HIDDEN_STYLE, wrapChildren, flatGesture, extendObject, omit, useNavigation, useRunOnJSCallback } from './utils';
26
26
  import { GestureDetector, Gesture } from 'react-native-gesture-handler';
27
27
  import Animated, { useSharedValue, useAnimatedStyle, withDecay, runOnJS, runOnUI, withSpring } from 'react-native-reanimated';
28
28
  import { collectDataset, noop } from '@mpxjs/utils';
@@ -100,15 +100,6 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
100
100
  layoutRef
101
101
  }, propsRef.current));
102
102
  }, []);
103
- // 节流版本的 change 事件触发
104
- const handleTriggerChangeThrottled = useCallback(({ x, y, type }) => {
105
- 'worklet';
106
- const now = Date.now();
107
- if (now - lastChangeTime.value >= changeThrottleTime) {
108
- lastChangeTime.value = now;
109
- runOnJS(handleTriggerChange)({ x, y, type });
110
- }
111
- }, [changeThrottleTime]);
112
103
  useEffect(() => {
113
104
  runOnUI(() => {
114
105
  if (offsetX.value !== x || offsetY.value !== y) {
@@ -130,7 +121,7 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
130
121
  : newY;
131
122
  }
132
123
  if (bindchange) {
133
- runOnJS(handleTriggerChange)({
124
+ runOnJS(runOnJSCallback)('handleTriggerChange', {
134
125
  x: newX,
135
126
  y: newY,
136
127
  type: 'setData'
@@ -295,13 +286,29 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
295
286
  bindtouchend && bindtouchend(e);
296
287
  catchtouchend && catchtouchend(e);
297
288
  };
289
+ const runOnJSCallbackRef = useRef({
290
+ handleTriggerChange,
291
+ triggerStartOnJS,
292
+ triggerMoveOnJS,
293
+ triggerEndOnJS
294
+ });
295
+ const runOnJSCallback = useRunOnJSCallback(runOnJSCallbackRef);
296
+ // 节流版本的 change 事件触发
297
+ const handleTriggerChangeThrottled = useCallback(({ x, y, type }) => {
298
+ 'worklet';
299
+ const now = Date.now();
300
+ if (now - lastChangeTime.value >= changeThrottleTime) {
301
+ lastChangeTime.value = now;
302
+ runOnJS(runOnJSCallback)('handleTriggerChange', { x, y, type });
303
+ }
304
+ }, [changeThrottleTime]);
298
305
  const gesture = useMemo(() => {
299
306
  const handleTriggerMove = (e) => {
300
307
  'worklet';
301
308
  const hasTouchmove = !!bindhtouchmove || !!bindvtouchmove || !!bindtouchmove;
302
309
  const hasCatchTouchmove = !!catchhtouchmove || !!catchvtouchmove || !!catchtouchmove;
303
310
  if (hasTouchmove || hasCatchTouchmove) {
304
- runOnJS(triggerMoveOnJS)({
311
+ runOnJS(runOnJSCallback)('triggerMoveOnJS', {
305
312
  e,
306
313
  touchEvent: touchEvent.value,
307
314
  hasTouchmove,
@@ -319,7 +326,7 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
319
326
  y: changedTouches.y
320
327
  };
321
328
  if (bindtouchstart || catchtouchstart) {
322
- runOnJS(triggerStartOnJS)({ e });
329
+ runOnJS(runOnJSCallback)('triggerStartOnJS', { e });
323
330
  }
324
331
  })
325
332
  .onStart(() => {
@@ -376,7 +383,7 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
376
383
  isFirstTouch.value = true;
377
384
  isMoving.value = false;
378
385
  if (bindtouchend || catchtouchend) {
379
- runOnJS(triggerEndOnJS)({ e });
386
+ runOnJS(runOnJSCallback)('triggerEndOnJS', { e });
380
387
  }
381
388
  })
382
389
  .onEnd((e) => {
@@ -405,7 +412,7 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
405
412
  : y;
406
413
  }
407
414
  if (bindchange) {
408
- runOnJS(handleTriggerChange)({
415
+ runOnJS(runOnJSCallback)('handleTriggerChange', {
409
416
  x,
410
417
  y
411
418
  });
@@ -423,7 +430,7 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
423
430
  }, () => {
424
431
  xInertialMotion.value = false;
425
432
  if (bindchange) {
426
- runOnJS(handleTriggerChange)({
433
+ runOnJS(runOnJSCallback)('handleTriggerChange', {
427
434
  x: offsetX.value,
428
435
  y: offsetY.value
429
436
  });
@@ -439,7 +446,7 @@ const _MovableView = forwardRef((movableViewProps, ref) => {
439
446
  }, () => {
440
447
  yInertialMotion.value = false;
441
448
  if (bindchange) {
442
- runOnJS(handleTriggerChange)({
449
+ runOnJS(runOnJSCallback)('handleTriggerChange', {
443
450
  x: offsetX.value,
444
451
  y: offsetY.value
445
452
  });
@@ -38,7 +38,7 @@ import Animated, { useSharedValue, withTiming, useAnimatedStyle, runOnJS } from
38
38
  import { warn, hasOwn } from '@mpxjs/utils';
39
39
  import useInnerProps, { getCustomEvent } from './getInnerListeners';
40
40
  import useNodesRef from './useNodesRef';
41
- import { splitProps, splitStyle, useTransformStyle, useLayout, wrapChildren, extendObject, flatGesture, HIDDEN_STYLE } from './utils';
41
+ import { splitProps, splitStyle, useTransformStyle, useLayout, wrapChildren, extendObject, flatGesture, HIDDEN_STYLE, useRunOnJSCallback } from './utils';
42
42
  import { IntersectionObserverContext, ScrollViewContext } from './context';
43
43
  import Portal from './mpx-portal';
44
44
  const AnimatedScrollView = RNAnimated.createAnimatedComponent(ScrollView);
@@ -79,6 +79,23 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
79
79
  const { normalStyle, hasVarDec, varContextRef, hasSelfPercent, hasPositionFixed, setWidth, setHeight } = useTransformStyle(style, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight });
80
80
  const { textStyle, innerStyle = {} } = splitStyle(normalStyle);
81
81
  const scrollViewRef = useRef(null);
82
+ const propsRef = useRef(props);
83
+ const refresherStateRef = useRef({
84
+ hasRefresher,
85
+ refresherTriggered
86
+ });
87
+ propsRef.current = props;
88
+ refresherStateRef.current = {
89
+ hasRefresher,
90
+ refresherTriggered
91
+ };
92
+ const runOnJSCallbackRef = useRef({
93
+ setEnableScroll,
94
+ setScrollBounces,
95
+ setRefreshing,
96
+ onRefresh
97
+ });
98
+ const runOnJSCallback = useRunOnJSCallback(runOnJSCallbackRef);
82
99
  useNodesRef(props, ref, scrollViewRef, {
83
100
  style: normalStyle,
84
101
  scrollOffset: scrollOptions,
@@ -343,6 +360,7 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
343
360
  }
344
361
  // 处理刷新
345
362
  function onRefresh() {
363
+ const { hasRefresher, refresherTriggered } = refresherStateRef.current;
346
364
  if (hasRefresher && refresherTriggered === undefined) {
347
365
  // 处理使用了自定义刷新组件,又没设置 refresherTriggered 的情况
348
366
  setRefreshing(true);
@@ -354,9 +372,9 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
354
372
  }
355
373
  }, 500);
356
374
  }
357
- const { bindrefresherrefresh } = props;
375
+ const { bindrefresherrefresh } = propsRef.current;
358
376
  bindrefresherrefresh &&
359
- bindrefresherrefresh(getCustomEvent('refresherrefresh', {}, { layoutRef }, props));
377
+ bindrefresherrefresh(getCustomEvent('refresherrefresh', {}, { layoutRef }, propsRef.current));
360
378
  }
361
379
  function getRefresherContent(children) {
362
380
  let refresherContent = null;
@@ -404,7 +422,7 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
404
422
  'worklet';
405
423
  if (enableScrollValue.value !== newValue) {
406
424
  enableScrollValue.value = newValue;
407
- runOnJS(setEnableScroll)(newValue);
425
+ runOnJS(runOnJSCallback)('setEnableScroll', newValue);
408
426
  }
409
427
  }
410
428
  const resetScrollState = (value) => {
@@ -415,7 +433,7 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
415
433
  'worklet';
416
434
  if (bouncesValue.value !== newValue) {
417
435
  bouncesValue.value = newValue;
418
- runOnJS(setScrollBounces)(newValue);
436
+ runOnJS(runOnJSCallback)('setScrollBounces', newValue);
419
437
  }
420
438
  }
421
439
  // 处理下拉刷新的手势
@@ -460,7 +478,7 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
460
478
  if ((event.translationY > 0 && translateY.value < refresherThreshold) || event.translationY < 0) {
461
479
  translateY.value = withTiming(0);
462
480
  updateScrollState(true);
463
- runOnJS(setRefreshing)(false);
481
+ runOnJS(runOnJSCallback)('setRefreshing', false);
464
482
  }
465
483
  else {
466
484
  translateY.value = withTiming(refresherHeight.value);
@@ -469,13 +487,13 @@ const _ScrollView = forwardRef((scrollViewProps = {}, ref) => {
469
487
  else if (event.translationY >= refresherHeight.value) {
470
488
  // 触发刷新
471
489
  translateY.value = withTiming(refresherHeight.value);
472
- runOnJS(onRefresh)();
490
+ runOnJS(runOnJSCallback)('onRefresh');
473
491
  }
474
492
  else {
475
493
  // 回弹
476
494
  translateY.value = withTiming(0);
477
495
  updateScrollState(true);
478
- runOnJS(setRefreshing)(false);
496
+ runOnJS(runOnJSCallback)('setRefreshing', false);
479
497
  }
480
498
  })
481
499
  .simultaneousWithExternalGesture(scrollViewRef);
@@ -4,7 +4,7 @@ import Animated, { useAnimatedStyle, useSharedValue, withTiming, Easing, runOnJS
4
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, extendObject, flatGesture } from './utils';
7
+ import { useTransformStyle, splitStyle, splitProps, useLayout, wrapChildren, extendObject, flatGesture, useRunOnJSCallback } from './utils';
8
8
  import { SwiperContext } from './context';
9
9
  import Portal from './mpx-portal';
10
10
  /**
@@ -71,7 +71,7 @@ const easeMap = {
71
71
  easeInOutCubic: Easing.inOut(Easing.cubic)
72
72
  };
73
73
  const SwiperWrapper = forwardRef((props, ref) => {
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, bindchange } = props;
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;
75
75
  const easeingFunc = props['easing-function'] || 'default';
76
76
  const easeDuration = props.duration || 500;
77
77
  const horizontal = props.vertical !== undefined ? !props.vertical : true;
@@ -112,14 +112,16 @@ const SwiperWrapper = forwardRef((props, ref) => {
112
112
  // 每个元素的宽度 or 高度,有固定值直接初始化无则0
113
113
  const step = useSharedValue(initStep);
114
114
  // 记录选中元素的索引值
115
- const currentIndex = useSharedValue(props.current || 0);
115
+ const currentIndex = useSharedValue(propCurrent);
116
116
  // const initOffset = getOffset(props.current || 0, initStep)
117
117
  // 记录元素的偏移量
118
- const offset = useSharedValue(getOffset(props.current || 0, initStep));
118
+ const offset = useSharedValue(getOffset(propCurrent, initStep));
119
119
  const strAbso = 'absolute' + dir.toUpperCase();
120
120
  const strVelocity = 'velocity' + dir.toUpperCase();
121
121
  // 标识手指触摸和抬起, 起点在onBegin
122
122
  const touchfinish = useSharedValue(true);
123
+ // 记录onUpdate时的方向,用于进行onFinalize中的值修正
124
+ const preUpdateTransDir = useSharedValue(0);
123
125
  // 记录上一帧的绝对定位坐标
124
126
  const preAbsolutePos = useSharedValue(0);
125
127
  // 记录从onBegin 到 onTouchesUp 时移动的距离
@@ -170,7 +172,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
170
172
  const iStep = dir === 'x' ? realWidth : realHeight;
171
173
  if (iStep !== step.value) {
172
174
  step.value = iStep;
173
- updateCurrent(props.current || 0, iStep);
175
+ updateCurrent(propCurrent, iStep);
174
176
  updateAutoplay();
175
177
  }
176
178
  }
@@ -272,7 +274,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
272
274
  easing: easeMap[easeingFunc]
273
275
  }, () => {
274
276
  currentIndex.value = nextIndex;
275
- runOnJS(loop)();
277
+ runOnJS(runOnJSCallback)('loop');
276
278
  });
277
279
  }
278
280
  else {
@@ -288,7 +290,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
288
290
  // 将开始位置设置为真正的位置
289
291
  offset.value = initOffset;
290
292
  currentIndex.value = nextIndex;
291
- runOnJS(loop)();
293
+ runOnJS(runOnJSCallback)('loop');
292
294
  });
293
295
  }
294
296
  else {
@@ -300,7 +302,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
300
302
  easing: easeMap[easeingFunc]
301
303
  }, () => {
302
304
  currentIndex.value = nextIndex;
303
- runOnJS(loop)();
305
+ runOnJS(runOnJSCallback)('loop');
304
306
  });
305
307
  }
306
308
  }
@@ -326,11 +328,16 @@ const SwiperWrapper = forwardRef((props, ref) => {
326
328
  };
327
329
  }, []);
328
330
  function handleSwiperChange(current) {
329
- if (props.current !== currentIndex.value) {
330
- const eventData = getCustomEvent('change', {}, { detail: { current, source: 'touch' }, layoutRef: layoutRef });
331
- bindchange && bindchange(eventData);
332
- }
331
+ const eventData = getCustomEvent('change', {}, { detail: { current, source: 'touch' }, layoutRef: layoutRef });
332
+ bindchange && bindchange(eventData);
333
333
  }
334
+ const runOnJSCallbackRef = useRef({
335
+ loop,
336
+ pauseLoop,
337
+ resumeLoop,
338
+ handleSwiperChange
339
+ });
340
+ const runOnJSCallback = useRunOnJSCallback(runOnJSCallbackRef);
334
341
  function getOffset(index, stepValue) {
335
342
  if (!stepValue)
336
343
  return 0;
@@ -348,12 +355,12 @@ const SwiperWrapper = forwardRef((props, ref) => {
348
355
  const targetOffset = getOffset(index || 0, stepValue);
349
356
  if (targetOffset !== offset.value) {
350
357
  // 内部基于props.current!==currentIndex.value决定是否使用动画及更新currentIndex.value
351
- if (props.current !== undefined && props.current !== currentIndex.value) {
358
+ if (propCurrent !== undefined && propCurrent !== currentIndex.value) {
352
359
  offset.value = withTiming(targetOffset, {
353
360
  duration: easeDuration,
354
361
  easing: easeMap[easeingFunc]
355
362
  }, () => {
356
- currentIndex.value = props.current || 0;
363
+ currentIndex.value = propCurrent;
357
364
  });
358
365
  }
359
366
  else {
@@ -372,8 +379,8 @@ const SwiperWrapper = forwardRef((props, ref) => {
372
379
  // 1. 用户在当前页切换选中项,动画;用户携带选中index打开到swiper页直接选中不走动画
373
380
  useAnimatedReaction(() => currentIndex.value, (newIndex, preIndex) => {
374
381
  // 这里必须传递函数名, 直接写()=> {}形式会报 访问了未sharedValue信息
375
- if (newIndex !== preIndex && bindchange) {
376
- runOnJS(handleSwiperChange)(newIndex);
382
+ if (newIndex !== preIndex && preIndex !== null && preIndex !== undefined && bindchange) {
383
+ runOnJS(runOnJSCallback)('handleSwiperChange', newIndex, propCurrent);
377
384
  }
378
385
  });
379
386
  useEffect(() => {
@@ -404,12 +411,12 @@ const SwiperWrapper = forwardRef((props, ref) => {
404
411
  }
405
412
  }, [children.length]);
406
413
  useEffect(() => {
407
- // 1. 如果用户在touch的过程中, 外部更新了current以外部为准(小程序表现)
414
+ // 1. 如果用户在touch的过程中, 外部更新了current以内部为准(小程序表现)
408
415
  // 2. 手指滑动过程中更新索引,外部会把current再传入进来,导致offset直接更新,增加判断不同才更新
409
- if (props.current !== currentIndex.value) {
410
- updateCurrent(props.current || 0, step.value);
416
+ if (propCurrent !== currentIndex.value && touchfinish.value) {
417
+ updateCurrent(propCurrent, step.value);
411
418
  }
412
- }, [props.current]);
419
+ }, [propCurrent]);
413
420
  useEffect(() => {
414
421
  autoplayShared.value = autoplay;
415
422
  updateAutoplay();
@@ -502,7 +509,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
502
509
  if (touchfinish.value !== false) {
503
510
  currentIndex.value = selectedIndex;
504
511
  offset.value = resetOffset;
505
- runOnJS(resumeLoop)();
512
+ runOnJS(runOnJSCallback)('resumeLoop');
506
513
  }
507
514
  });
508
515
  }
@@ -513,7 +520,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
513
520
  }, () => {
514
521
  if (touchfinish.value !== false) {
515
522
  currentIndex.value = selectedIndex;
516
- runOnJS(resumeLoop)();
523
+ runOnJS(runOnJSCallback)('resumeLoop');
517
524
  }
518
525
  });
519
526
  }
@@ -535,7 +542,7 @@ const SwiperWrapper = forwardRef((props, ref) => {
535
542
  }, () => {
536
543
  if (touchfinish.value !== false) {
537
544
  currentIndex.value = moveToIndex;
538
- runOnJS(resumeLoop)();
545
+ runOnJS(runOnJSCallback)('resumeLoop');
539
546
  }
540
547
  });
541
548
  }
@@ -562,20 +569,11 @@ const SwiperWrapper = forwardRef((props, ref) => {
562
569
  'worklet';
563
570
  const { diffOffset, half, isTriggerUpdateHalf } = computeHalf(eventData);
564
571
  if (+diffOffset === 0) {
565
- runOnJS(resumeLoop)();
572
+ runOnJS(runOnJSCallback)('resumeLoop');
566
573
  }
567
574
  else if (isTriggerUpdateHalf) {
568
- // 如果触发了onUpdate时的索引变更,则直接以update时的index为准
569
- const targetIndex = !circularShared.value ? currentIndex.value : currentIndex.value + patchElmNumShared.value - 1;
570
- offset.value = withTiming(-targetIndex * step.value, {
571
- duration: easeDuration,
572
- easing: easeMap[easeingFunc]
573
- }, () => {
574
- if (touchfinish.value !== false) {
575
- currentIndex.value = targetIndex;
576
- runOnJS(resumeLoop)();
577
- }
578
- });
575
+ // 如果触发了onUpdate时的索引变更
576
+ handleEnd(eventData);
579
577
  }
580
578
  else if (half) {
581
579
  handleEnd(eventData);
@@ -651,19 +649,20 @@ const SwiperWrapper = forwardRef((props, ref) => {
651
649
  return;
652
650
  touchfinish.value = false;
653
651
  cancelAnimation(offset);
654
- runOnJS(pauseLoop)();
652
+ runOnJS(runOnJSCallback)('pauseLoop');
655
653
  preAbsolutePos.value = e[strAbso];
656
654
  moveTranstion.value = e[strAbso];
657
655
  })
658
656
  .onUpdate((e) => {
659
657
  'worklet';
660
- if (touchfinish.value)
661
- return;
662
658
  const moveDistance = e[strAbso] - preAbsolutePos.value;
659
+ if (touchfinish.value || moveDistance === 0)
660
+ return;
663
661
  const eventData = {
664
662
  translation: moveDistance,
665
- transdir: moveDistance !== 0 ? moveDistance : e[strAbso] - moveTranstion.value
663
+ transdir: moveDistance
666
664
  };
665
+ preUpdateTransDir.value = moveDistance;
667
666
  // 1. 支持滑动中超出一半更新索引的能力:只更新索引并不会影响onFinalize依据当前offset计算的索引
668
667
  const { half } = computeHalf(eventData);
669
668
  if (childrenLength.value > 1 && half) {
@@ -704,11 +703,17 @@ const SwiperWrapper = forwardRef((props, ref) => {
704
703
  if (touchfinish.value)
705
704
  return;
706
705
  touchfinish.value = true;
706
+ /**
707
+ * 安卓修正
708
+ * 问题:部分安卓机型onFinalize中拿到的absoluteX 有问题
709
+ * 案例:比如手指从右向左滑的时候,onUpdate拿到的是241.64346313476562, 而onFinalize中拿到的是241.81817626953125,理论上onFinalize中应该比onUpdate小才对吧
710
+ * 解决方式:修正
711
+ */
707
712
  // 触发过onUpdate正常情况下e[strAbso] - preAbsolutePos.value=0; 未触发过onUpdate的情况下e[strAbso] - preAbsolutePos.value 不为0
708
713
  const moveDistance = e[strAbso] - preAbsolutePos.value;
709
714
  const eventData = {
710
715
  translation: moveDistance,
711
- transdir: moveDistance !== 0 ? moveDistance : e[strAbso] - moveTranstion.value
716
+ transdir: Math.abs(moveDistance) > 1 ? moveDistance : preUpdateTransDir.value
712
717
  };
713
718
  // 1. 只有一个元素:循环 和 非循环状态,都走回弹效果
714
719
  if (childrenLength.value === 1) {
@@ -203,16 +203,13 @@ function backgroundSize(imageProps, preImageInfo, imageSize, layoutInfo) {
203
203
  else { // 数值类型 ImageStyle
204
204
  // 数值类型设置为 stretch
205
205
  imageProps.resizeMode = 'stretch';
206
- if (type === 'linear') {
207
- const dimensionWidth = calcPercent(width, layoutWidth) || 0;
208
- const dimensionHeight = calcPercent(height, layoutHeight) || 0;
209
- // ios 上 linear 组件只要重新触发渲染,在渲染过程中 width 或者 height 被设置为 0,即使后面再更新为正常宽高,也会渲染不出来
210
- if (dimensionWidth && dimensionHeight) {
211
- dimensions = {
212
- width: dimensionWidth,
213
- height: dimensionHeight
214
- };
215
- }
206
+ if (type === 'linear' && (!layoutWidth || !layoutHeight)) {
207
+ // ios linear 组件只要重新触发渲染,在渲染过程中外层容器 width 或者 height 被设置为 0,通过设置 % 的方式会渲染不出来,即使后面再更新为正常宽高也渲染不出来
208
+ // 所以 hack 手动先将 linear 宽高也设置为 0,后面再更新为正确的数值或 %。
209
+ dimensions = {
210
+ width: 0,
211
+ height: 0
212
+ };
216
213
  }
217
214
  else {
218
215
  dimensions = {
@@ -22,7 +22,7 @@ import { StyleSheet, View, LayoutChangeEvent } from 'react-native'
22
22
  import useInnerProps, { getCustomEvent } from './getInnerListeners'
23
23
  import useNodesRef, { HandlerRef } from './useNodesRef'
24
24
  import { MovableAreaContext } from './context'
25
- import { useTransformStyle, splitProps, splitStyle, HIDDEN_STYLE, wrapChildren, GestureHandler, flatGesture, extendObject, omit, useNavigation } from './utils'
25
+ import { useTransformStyle, splitProps, splitStyle, HIDDEN_STYLE, wrapChildren, GestureHandler, flatGesture, extendObject, omit, useNavigation, useRunOnJSCallback } from './utils'
26
26
  import { GestureDetector, Gesture, GestureTouchEvent, GestureStateChangeEvent, PanGestureHandlerEventPayload, PanGesture } from 'react-native-gesture-handler'
27
27
  import Animated, {
28
28
  useSharedValue,
@@ -30,7 +30,6 @@ import Animated, {
30
30
  withDecay,
31
31
  runOnJS,
32
32
  runOnUI,
33
- useAnimatedReaction,
34
33
  withSpring
35
34
  } from 'react-native-reanimated'
36
35
  import { collectDataset, noop } from '@mpxjs/utils'
@@ -87,7 +86,6 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
87
86
  const layoutRef = useRef<any>({})
88
87
  const changeSource = useRef<any>('')
89
88
  const hasLayoutRef = useRef(false)
90
-
91
89
  const propsRef = useRef<any>({})
92
90
  propsRef.current = (props || {}) as MovableViewProps
93
91
 
@@ -202,16 +200,6 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
202
200
  )
203
201
  }, [])
204
202
 
205
- // 节流版本的 change 事件触发
206
- const handleTriggerChangeThrottled = useCallback(({ x, y, type }: { x: number; y: number; type?: string }) => {
207
- 'worklet'
208
- const now = Date.now()
209
- if (now - lastChangeTime.value >= changeThrottleTime) {
210
- lastChangeTime.value = now
211
- runOnJS(handleTriggerChange)({ x, y, type })
212
- }
213
- }, [changeThrottleTime])
214
-
215
203
  useEffect(() => {
216
204
  runOnUI(() => {
217
205
  if (offsetX.value !== x || offsetY.value !== y) {
@@ -233,7 +221,7 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
233
221
  : newY
234
222
  }
235
223
  if (bindchange) {
236
- runOnJS(handleTriggerChange)({
224
+ runOnJS(runOnJSCallback)('handleTriggerChange', {
237
225
  x: newX,
238
226
  y: newY,
239
227
  type: 'setData'
@@ -408,13 +396,31 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
408
396
  catchtouchend && catchtouchend(e)
409
397
  }
410
398
 
399
+ const runOnJSCallbackRef = useRef({
400
+ handleTriggerChange,
401
+ triggerStartOnJS,
402
+ triggerMoveOnJS,
403
+ triggerEndOnJS
404
+ })
405
+ const runOnJSCallback = useRunOnJSCallback(runOnJSCallbackRef)
406
+
407
+ // 节流版本的 change 事件触发
408
+ const handleTriggerChangeThrottled = useCallback(({ x, y, type }: { x: number; y: number; type?: string }) => {
409
+ 'worklet'
410
+ const now = Date.now()
411
+ if (now - lastChangeTime.value >= changeThrottleTime) {
412
+ lastChangeTime.value = now
413
+ runOnJS(runOnJSCallback)('handleTriggerChange', { x, y, type })
414
+ }
415
+ }, [changeThrottleTime])
416
+
411
417
  const gesture = useMemo(() => {
412
418
  const handleTriggerMove = (e: GestureTouchEvent) => {
413
419
  'worklet'
414
420
  const hasTouchmove = !!bindhtouchmove || !!bindvtouchmove || !!bindtouchmove
415
421
  const hasCatchTouchmove = !!catchhtouchmove || !!catchvtouchmove || !!catchtouchmove
416
422
  if (hasTouchmove || hasCatchTouchmove) {
417
- runOnJS(triggerMoveOnJS)({
423
+ runOnJS(runOnJSCallback)('triggerMoveOnJS', {
418
424
  e,
419
425
  touchEvent: touchEvent.value,
420
426
  hasTouchmove,
@@ -433,7 +439,7 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
433
439
  y: changedTouches.y
434
440
  }
435
441
  if (bindtouchstart || catchtouchstart) {
436
- runOnJS(triggerStartOnJS)({ e })
442
+ runOnJS(runOnJSCallback)('triggerStartOnJS', { e })
437
443
  }
438
444
  })
439
445
  .onStart(() => {
@@ -487,7 +493,7 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
487
493
  isFirstTouch.value = true
488
494
  isMoving.value = false
489
495
  if (bindtouchend || catchtouchend) {
490
- runOnJS(triggerEndOnJS)({ e })
496
+ runOnJS(runOnJSCallback)('triggerEndOnJS', { e })
491
497
  }
492
498
  })
493
499
  .onEnd((e: GestureStateChangeEvent<PanGestureHandlerEventPayload>) => {
@@ -515,7 +521,7 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
515
521
  : y
516
522
  }
517
523
  if (bindchange) {
518
- runOnJS(handleTriggerChange)({
524
+ runOnJS(runOnJSCallback)('handleTriggerChange', {
519
525
  x,
520
526
  y
521
527
  })
@@ -532,7 +538,7 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
532
538
  }, () => {
533
539
  xInertialMotion.value = false
534
540
  if (bindchange) {
535
- runOnJS(handleTriggerChange)({
541
+ runOnJS(runOnJSCallback)('handleTriggerChange', {
536
542
  x: offsetX.value,
537
543
  y: offsetY.value
538
544
  })
@@ -548,7 +554,7 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
548
554
  }, () => {
549
555
  yInertialMotion.value = false
550
556
  if (bindchange) {
551
- runOnJS(handleTriggerChange)({
557
+ runOnJS(runOnJSCallback)('handleTriggerChange', {
552
558
  x: offsetX.value,
553
559
  y: offsetY.value
554
560
  })