@mpxjs/webpack-plugin 2.10.7-beta.9 → 2.10.8-beta.1

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 (46) hide show
  1. package/lib/dependencies/RequireExternalDependency.js +61 -0
  2. package/lib/file-loader.js +3 -2
  3. package/lib/index.js +60 -15
  4. package/lib/json-compiler/index.js +1 -0
  5. package/lib/parser.js +1 -1
  6. package/lib/platform/json/wx/index.js +43 -25
  7. package/lib/platform/template/wx/component-config/fix-component-name.js +2 -2
  8. package/lib/platform/template/wx/component-config/index.js +2 -0
  9. package/lib/platform/template/wx/component-config/movable-view.js +10 -1
  10. package/lib/platform/template/wx/component-config/page-container.js +19 -0
  11. package/lib/platform/template/wx/component-config/unsupported.js +1 -1
  12. package/lib/platform/template/wx/index.js +2 -1
  13. package/lib/react/LoadAsyncChunkModule.js +74 -0
  14. package/lib/react/index.js +3 -1
  15. package/lib/react/processJSON.js +74 -13
  16. package/lib/react/processScript.js +6 -6
  17. package/lib/react/script-helper.js +100 -41
  18. package/lib/runtime/components/react/context.ts +2 -12
  19. package/lib/runtime/components/react/dist/context.js +1 -1
  20. package/lib/runtime/components/react/dist/getInnerListeners.js +1 -1
  21. package/lib/runtime/components/react/dist/mpx-async-suspense.jsx +135 -0
  22. package/lib/runtime/components/react/dist/mpx-movable-area.jsx +9 -63
  23. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +58 -301
  24. package/lib/runtime/components/react/dist/mpx-page-container.jsx +255 -0
  25. package/lib/runtime/components/react/dist/mpx-swiper.jsx +30 -55
  26. package/lib/runtime/components/react/dist/mpx-web-view.jsx +14 -28
  27. package/lib/runtime/components/react/dist/useAnimationHooks.js +2 -87
  28. package/lib/runtime/components/react/getInnerListeners.ts +1 -1
  29. package/lib/runtime/components/react/mpx-async-suspense.tsx +180 -0
  30. package/lib/runtime/components/react/mpx-movable-area.tsx +11 -98
  31. package/lib/runtime/components/react/mpx-movable-view.tsx +60 -350
  32. package/lib/runtime/components/react/mpx-page-container.tsx +394 -0
  33. package/lib/runtime/components/react/mpx-swiper.tsx +29 -55
  34. package/lib/runtime/components/react/mpx-web-view.tsx +13 -33
  35. package/lib/runtime/components/react/types/global.d.ts +15 -0
  36. package/lib/runtime/components/react/useAnimationHooks.ts +2 -85
  37. package/lib/runtime/optionProcessorReact.d.ts +18 -0
  38. package/lib/runtime/optionProcessorReact.js +30 -0
  39. package/lib/script-setup-compiler/index.js +27 -5
  40. package/lib/template-compiler/compiler.js +27 -6
  41. package/lib/utils/dom-tag-config.js +18 -4
  42. package/lib/utils/trans-async-sub-rules.js +19 -0
  43. package/lib/web/script-helper.js +1 -1
  44. package/package.json +3 -3
  45. package/lib/runtime/components/react/AsyncContainer.tsx +0 -189
  46. package/lib/runtime/components/react/dist/AsyncContainer.jsx +0 -141
@@ -0,0 +1,394 @@
1
+ import React, { createElement, forwardRef, useEffect, useRef, useState } from 'react'
2
+ import {
3
+ StyleSheet,
4
+ Animated,
5
+ Dimensions,
6
+ TouchableWithoutFeedback,
7
+ PanResponder,
8
+ StyleProp,
9
+ ViewStyle
10
+ } from 'react-native'
11
+ import Portal from './mpx-portal/index'
12
+ import { PreventRemoveEvent, usePreventRemove } from '@react-navigation/native'
13
+ import { extendObject, useLayout, useNavigation } from './utils'
14
+ import useInnerProps, { getCustomEvent } from './getInnerListeners'
15
+ import useNodesRef from './useNodesRef'
16
+
17
+ type Position = 'top' | 'bottom' | 'right' | 'center';
18
+
19
+ interface PageContainerProps {
20
+ show: boolean;
21
+ duration?: number;
22
+ 'z-index'?: number;
23
+ overlay?: boolean;
24
+ position?: Position;
25
+ round?: boolean;
26
+ 'close-on-slide-down'?: boolean;
27
+ 'overlay-style'?: StyleProp<ViewStyle>;
28
+ 'custom-style'?: StyleProp<ViewStyle>;
29
+
30
+ bindclose: (event: CustomEvent<{ value: boolean}>) => void;
31
+
32
+ bindbeforeenter?: (event: CustomEvent) => void;
33
+ bindenter?: (event: CustomEvent) => void;
34
+ bindafterenter?: (event: CustomEvent) => void;
35
+ bindbeforeleave?: (event: CustomEvent) => void;
36
+ bindleave?: (event: CustomEvent) => void;
37
+ bindafterleave?: (event: CustomEvent) => void;
38
+ bindclickoverlay?: (event: CustomEvent) => void;
39
+ children: React.ReactNode;
40
+ }
41
+
42
+ const screenHeight = Dimensions.get('window').height
43
+ const screenWidth = Dimensions.get('window').width
44
+
45
+ function nextTick (cb: () => void) {
46
+ setTimeout(cb, 0)
47
+ }
48
+
49
+ export default forwardRef<any, PageContainerProps>((props, ref) => {
50
+ const {
51
+ show,
52
+ duration = 300,
53
+ 'z-index': zIndex = 100,
54
+ overlay = true,
55
+ position = 'bottom',
56
+ round = false,
57
+ 'close-on-slide-down': closeOnSlideDown = false,
58
+ 'overlay-style': overlayStyle,
59
+ 'custom-style': customStyle,
60
+ bindclose, // RN下特有属性,用于同步show状态到父组件
61
+ bindbeforeenter,
62
+ bindenter,
63
+ bindafterenter,
64
+ bindbeforeleave,
65
+ bindleave,
66
+ bindafterleave,
67
+ bindclickoverlay,
68
+ children
69
+ } = props
70
+
71
+ const isFirstRenderFlag = useRef(true)
72
+ const isFirstRender = isFirstRenderFlag.current
73
+ if (isFirstRenderFlag.current) {
74
+ isFirstRenderFlag.current = false
75
+ }
76
+
77
+ const close = () => {
78
+ bindclose(getCustomEvent(
79
+ 'close',
80
+ {},
81
+ { detail: { value: false, source: 'close' } },
82
+ props
83
+ ))
84
+ }
85
+
86
+ const [internalVisible, setInternalVisible] = useState(show) // 控制组件是否挂载
87
+
88
+ const overlayOpacity = useRef(new Animated.Value(0)).current
89
+ const contentOpacity = useRef(new Animated.Value(position === 'center' ? 0 : 1)).current
90
+ const contentTranslate = useRef(new Animated.Value(getInitialPosition())).current
91
+
92
+ const currentAnimation = useRef<Array<Animated.CompositeAnimation> | null>(null)
93
+
94
+ function getInitialPosition () {
95
+ switch (position) {
96
+ case 'top':
97
+ return -screenHeight
98
+ case 'bottom':
99
+ return screenHeight
100
+ case 'right':
101
+ return screenWidth
102
+ case 'center':
103
+ return 0
104
+ default:
105
+ return screenHeight
106
+ }
107
+ }
108
+
109
+ const currentTick = useRef(0)
110
+ function createTick () {
111
+ currentTick.current++
112
+ console.log('currentTick.current++', currentTick.current)
113
+ const current = currentTick.current
114
+ return () => {
115
+ console.log('currentTick.current', currentTick.current, 'current', current)
116
+ return currentTick.current === current
117
+ }
118
+ }
119
+ // 播放入场动画
120
+ const animateIn = () => {
121
+ const isCurrentTick = createTick()
122
+ const animateOutFinish = currentAnimation.current === null
123
+ if (!animateOutFinish) {
124
+ currentAnimation.current!.forEach((animation) => animation.stop())
125
+ }
126
+ const animations: Animated.CompositeAnimation[] = [
127
+ Animated.timing(contentTranslate, {
128
+ toValue: 0,
129
+ duration,
130
+ useNativeDriver: true
131
+ }),
132
+ Animated.timing(contentOpacity, {
133
+ toValue: 1,
134
+ duration,
135
+ useNativeDriver: true
136
+ }),
137
+ Animated.timing(overlayOpacity, {
138
+ toValue: 1,
139
+ duration,
140
+ useNativeDriver: true
141
+ })
142
+ ]
143
+ currentAnimation.current = animations
144
+ // 所有生命周期需相隔一个nextTick以保证在生命周期中修改show可在组件内部监听到
145
+ bindbeforeenter && bindbeforeenter(getCustomEvent(
146
+ 'beforeenter',
147
+ {},
148
+ { detail: { value: false, source: 'beforeenter' } },
149
+ props
150
+ ))
151
+ nextTick(() => {
152
+ bindenter && bindenter(getCustomEvent(
153
+ 'enter',
154
+ {},
155
+ { detail: { value: false, source: 'enter' } },
156
+ props
157
+ ))
158
+ // 与微信对其, bindenter 需要执行,所以 isCurrentTick 放在后面
159
+ if (!isCurrentTick()) return
160
+
161
+ console.log('animateIn start')
162
+ // 设置为动画初始状态(特殊情况, 如果退场动画没有结束 或者 退场动画还未开始,则无需初始化,而是从当前位置完成动画)
163
+ if (animateOutFinish) {
164
+ contentTranslate.setValue(getInitialPosition())
165
+ contentOpacity.setValue(position === 'center' ? 0 : 1)
166
+ }
167
+ Animated.parallel(animations).start(() => {
168
+ bindafterenter && bindafterenter(getCustomEvent(
169
+ 'afterenter',
170
+ {},
171
+ { detail: { value: false, source: 'afterenter' } },
172
+ props
173
+ ))
174
+ })
175
+ })
176
+ }
177
+
178
+ // 播放离场动画
179
+ const animateOut = () => {
180
+ const isCurrentTick = createTick()
181
+ // 停止入场动画
182
+ currentAnimation.current?.forEach((animation) => animation.stop())
183
+ const animations: Animated.CompositeAnimation[] = [Animated.timing(overlayOpacity, {
184
+ toValue: 0,
185
+ duration,
186
+ useNativeDriver: true
187
+ })
188
+ ]
189
+ if (position === 'center') {
190
+ animations.push(Animated.timing(contentOpacity, {
191
+ toValue: 0,
192
+ duration,
193
+ useNativeDriver: true
194
+ }))
195
+ } else {
196
+ animations.push(Animated.timing(contentTranslate, {
197
+ toValue: getInitialPosition(),
198
+ duration,
199
+ useNativeDriver: true
200
+ }))
201
+ }
202
+ currentAnimation.current = animations
203
+ bindbeforeleave && bindbeforeleave(getCustomEvent(
204
+ 'beforeleave',
205
+ {},
206
+ { detail: { value: false, source: 'beforeleave' } },
207
+ props
208
+ ))
209
+ nextTick(() => {
210
+ bindleave && bindleave(getCustomEvent(
211
+ 'leave',
212
+ {},
213
+ { detail: { value: false, source: 'leave' } },
214
+ props
215
+ ))
216
+ if (!isCurrentTick()) return
217
+ console.log('animateOut start')
218
+ Animated.parallel(animations).start(() => {
219
+ currentAnimation.current = null
220
+ bindafterleave && bindafterleave(getCustomEvent(
221
+ 'afterleave',
222
+ {},
223
+ { detail: { value: false, source: 'afterleave' } },
224
+ props
225
+ ))
226
+ setInternalVisible(false) // 动画播放完后,才卸载
227
+ })
228
+ })
229
+ }
230
+
231
+ useEffect(() => {
232
+ console.log('====comp show', show, 'internalVisible', internalVisible)
233
+ // 如果展示状态和挂载状态一致,则不需要做任何操作
234
+ if (show) {
235
+ setInternalVisible(true) // 确保挂载
236
+ animateIn()
237
+ } else {
238
+ if (!isFirstRender) animateOut()
239
+ }
240
+ }, [show])
241
+
242
+ const navigation = useNavigation()
243
+ usePreventRemove(show, (event: PreventRemoveEvent) => {
244
+ const { data } = event
245
+ if (show) {
246
+ close()
247
+ } else {
248
+ navigation?.dispatch(data.action)
249
+ }
250
+ })
251
+
252
+ // IOS 下需要关闭手势返回(原因: IOS手势返回时页面会跟随手指滑动,但是实际返回动作是在松手时触发,需禁掉页面跟随手指滑动的效果)
253
+ useEffect(() => {
254
+ navigation?.setOptions({
255
+ gestureEnabled: !show
256
+ })
257
+ }, [show])
258
+
259
+ const SCREEN_EDGE_THRESHOLD = 60 // 从屏幕左侧 30px 内触发
260
+
261
+ // 内容区 手势下滑关闭
262
+ const contentPanResponder = PanResponder.create({
263
+ onMoveShouldSetPanResponder: (_, gestureState) => {
264
+ const { dx, dy } = gestureState
265
+ return dy > 200 && Math.abs(dx) < 60
266
+ },
267
+ onPanResponderRelease: () => {
268
+ close()
269
+ }
270
+ })
271
+
272
+ // 全屏幕 IOS 右滑手势返回
273
+ const screenPanResponder = PanResponder.create({
274
+ onMoveShouldSetPanResponder: (_, gestureState) => {
275
+ const { moveX, dx, dy } = gestureState
276
+
277
+ const isFromEdge = moveX < SCREEN_EDGE_THRESHOLD
278
+ const isHorizontalSwipe = dx > 10 && Math.abs(dy) < 20
279
+ return isFromEdge && isHorizontalSwipe
280
+ },
281
+ onPanResponderRelease: (_, gestureState) => {
282
+ if (gestureState.dx > 100) {
283
+ close()
284
+ }
285
+ }
286
+ })
287
+
288
+ const getTransformStyle: () => ViewStyle = () => {
289
+ switch (position) {
290
+ case 'top':
291
+ case 'bottom':
292
+ return { transform: [{ translateY: contentTranslate }] }
293
+ case 'right':
294
+ return { transform: [{ translateX: contentTranslate }] }
295
+ case 'center':
296
+ return {}
297
+ }
298
+ }
299
+
300
+ const renderMask = () => {
301
+ const onPress = () => {
302
+ close()
303
+ bindclickoverlay && bindclickoverlay(getCustomEvent(
304
+ 'clickoverlay',
305
+ {},
306
+ { detail: { value: false, source: 'clickoverlay' } },
307
+ props
308
+ ))
309
+ }
310
+ return createElement(TouchableWithoutFeedback, { onPress },
311
+ createElement(Animated.View, { style: [styles.overlay, overlayStyle, { opacity: overlayOpacity }] }))
312
+ }
313
+
314
+ const renderContent = (children: React.ReactNode) => {
315
+ const contentProps = extendObject(
316
+ {
317
+ style: [
318
+ styles.container,
319
+ round ? styles.rounded : null,
320
+ positionStyle[position],
321
+ customStyle,
322
+ getTransformStyle(),
323
+ { opacity: contentOpacity }
324
+ ]
325
+ },
326
+ closeOnSlideDown ? contentPanResponder.panHandlers : null
327
+ )
328
+ return createElement(Animated.View, contentProps, children)
329
+ }
330
+
331
+ const nodeRef = useRef(null)
332
+ useNodesRef(props, ref, nodeRef, {})
333
+ const { layoutRef, layoutProps } = useLayout({ props, hasSelfPercent: false, nodeRef })
334
+ const innerProps = useInnerProps(
335
+ extendObject(
336
+ {},
337
+ props,
338
+ {
339
+ ref: nodeRef
340
+ },
341
+ layoutProps
342
+ ),
343
+ [],
344
+ { layoutRef }
345
+ )
346
+ const wrapperProps = extendObject(
347
+ innerProps,
348
+ {
349
+ style: [styles.wrapper, { zIndex }]
350
+ },
351
+ __mpx_mode__ === 'ios' ? screenPanResponder.panHandlers : {}
352
+ )
353
+
354
+ // TODO 是否有必要支持refs? dataset?
355
+ return createElement(Portal, null,
356
+ internalVisible
357
+ ? createElement(Animated.View, wrapperProps,
358
+ overlay ? renderMask() : null,
359
+ renderContent(children)
360
+ )
361
+ : null
362
+ )
363
+ })
364
+
365
+ const styles = StyleSheet.create({
366
+ wrapper: extendObject(
367
+ {
368
+ justifyContent: 'flex-end',
369
+ alignItems: 'center'
370
+ } as const,
371
+ StyleSheet.absoluteFillObject
372
+ ),
373
+ overlay: extendObject(
374
+ {
375
+ backgroundColor: 'rgba(0,0,0,0.5)'
376
+ },
377
+ StyleSheet.absoluteFillObject
378
+ ),
379
+ container: {
380
+ position: 'absolute',
381
+ backgroundColor: 'white'
382
+ },
383
+ rounded: {
384
+ borderTopLeftRadius: 20,
385
+ borderTopRightRadius: 20
386
+ }
387
+ })
388
+
389
+ const positionStyle: Record<Position, ViewStyle> = {
390
+ bottom: { bottom: 0, width: '100%', height: 'auto' },
391
+ top: { top: 0, width: '100%', height: 'auto' },
392
+ right: extendObject({}, StyleSheet.absoluteFillObject, { right: 0 }),
393
+ center: extendObject({}, StyleSheet.absoluteFillObject)
394
+ }
@@ -23,7 +23,6 @@ import Portal from './mpx-portal'
23
23
  * ✔ easing-function ="easeOutCubic"
24
24
  * ✘ display-multiple-items
25
25
  * ✘ snap-to-edge
26
- * ✔ disableGesture
27
26
  */
28
27
  type EaseType = 'default' | 'linear' | 'easeInCubic' | 'easeOutCubic' | 'easeInOutCubic'
29
28
  type StrAbsoType = 'absoluteX' | 'absoluteY'
@@ -144,7 +143,8 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
144
143
  style = {},
145
144
  autoplay = false,
146
145
  circular = false,
147
- disableGesture = false
146
+ disableGesture = false,
147
+ bindchange
148
148
  } = props
149
149
  const easeingFunc = props['easing-function'] || 'default'
150
150
  const easeDuration = props.duration || 500
@@ -207,10 +207,6 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
207
207
  const moveTranstion = useSharedValue(0)
208
208
  // 记录从onBegin 到 onTouchesUp 的时间
209
209
  const moveTime = useSharedValue(0)
210
- // 记录从onBegin 到 onTouchesCancelled 另外一个方向移动的距离
211
- const anotherDirectionMove = useSharedValue(0)
212
- // 另一个方向的
213
- const anotherAbso = 'absolute' + (dir === 'x' ? 'y' : 'x').toUpperCase() as StrAbsoType
214
210
  const timerId = useRef(0 as number | ReturnType<typeof setTimeout>)
215
211
  const intervalTimer = props.interval || 500
216
212
 
@@ -433,6 +429,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
433
429
  if (props.current !== currentIndex.value) {
434
430
  const eventData = getCustomEvent('change', {}, { detail: { current, source: 'touch' }, layoutRef: layoutRef })
435
431
  props.bindchange && props.bindchange(eventData)
432
+ bindchange && bindchange(eventData)
436
433
  }
437
434
  }
438
435
 
@@ -474,7 +471,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
474
471
  // 1. 用户在当前页切换选中项,动画;用户携带选中index打开到swiper页直接选中不走动画
475
472
  useAnimatedReaction(() => currentIndex.value, (newIndex: number, preIndex: number) => {
476
473
  // 这里必须传递函数名, 直接写()=> {}形式会报 访问了未sharedValue信息
477
- if (newIndex !== preIndex && props.bindchange) {
474
+ if (newIndex !== preIndex && bindchange) {
478
475
  runOnJS(handleSwiperChange)(newIndex)
479
476
  }
480
477
  })
@@ -509,11 +506,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
509
506
  }, [children.length])
510
507
 
511
508
  useEffect(() => {
512
- // 1. 如果用户在touch的过程中, 外部更新了current以外部为准(小程序表现)
513
- // 2. 手指滑动过程中更新索引,外部会把current再穿进来,导致offset直接更新了
514
- if (props.current !== currentIndex.value) {
515
- updateCurrent(props.current || 0, step.value)
516
- }
509
+ updateCurrent(props.current || 0, step.value)
517
510
  }, [props.current])
518
511
 
519
512
  useEffect(() => {
@@ -575,25 +568,18 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
575
568
  targetOffset: -moveToTargetPos
576
569
  }
577
570
  }
578
- function checkUnCircular (eventData: EventDataType) {
571
+ function canMove (eventData: EventDataType) {
579
572
  'worklet'
580
573
  const { translation } = eventData
581
574
  const currentOffset = Math.abs(offset.value)
582
- // 向右滑动swiper
583
- if (translation < 0) {
584
- const boundaryOffset = step.value * (childrenLength.value - 1)
585
- const gestureMovePos = Math.abs(translation) + currentOffset
586
- return {
587
- // 防止快速连续向右滑动时,手势移动的距离 加 当前的offset超出边界
588
- targetOffset: gestureMovePos > boundaryOffset ? -boundaryOffset : offset.value + translation,
589
- canMove: currentOffset < boundaryOffset
575
+ if (!circularShared.value) {
576
+ if (translation < 0) {
577
+ return currentOffset < step.value * (childrenLength.value - 1)
578
+ } else {
579
+ return currentOffset > 0
590
580
  }
591
581
  } else {
592
- const gestureMovePos = currentOffset - translation
593
- return {
594
- targetOffset: gestureMovePos < 0 ? 0 : offset.value + translation,
595
- canMove: currentOffset > 0
596
- }
582
+ return true
597
583
  }
598
584
  }
599
585
  function handleEnd (eventData: EventDataType) {
@@ -652,7 +638,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
652
638
  }
653
639
  })
654
640
  }
655
- function computeHalf () {
641
+ function handleLongPress () {
656
642
  'worklet'
657
643
  const currentOffset = Math.abs(offset.value)
658
644
  let preOffset = (currentIndex.value + patchElmNumShared.value) * step.value
@@ -662,14 +648,6 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
662
648
  // 正常事件中拿到的transition值(正向滑动<0,倒着滑>0)
663
649
  const diffOffset = preOffset - currentOffset
664
650
  const half = Math.abs(diffOffset) > step.value / 2
665
- return {
666
- diffOffset,
667
- half
668
- }
669
- }
670
- function handleLongPress () {
671
- 'worklet'
672
- const { diffOffset, half } = computeHalf()
673
651
  if (+diffOffset === 0) {
674
652
  runOnJS(resumeLoop)()
675
653
  } else if (half) {
@@ -725,29 +703,18 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
725
703
  runOnJS(pauseLoop)()
726
704
  preAbsolutePos.value = e[strAbso]
727
705
  moveTranstion.value = e[strAbso]
728
- anotherDirectionMove.value = e[anotherAbso]
729
706
  moveTime.value = new Date().getTime()
730
707
  })
731
- .onUpdate((e) => {
708
+ .onTouchesMove((e) => {
732
709
  'worklet'
733
710
  if (touchfinish.value) return
734
- const moveDistance = e[strAbso] - preAbsolutePos.value
711
+ const touchEventData = e.changedTouches[0]
712
+ const moveDistance = touchEventData[strAbso] - preAbsolutePos.value
735
713
  const eventData = {
736
714
  translation: moveDistance
737
715
  }
738
- // 1. 在Move过程中,如果手指一直没抬起来,超过一半的话也会更新索引
739
- const { half } = computeHalf()
740
- if (half) {
741
- const { selectedIndex } = getTargetPosition(eventData)
742
- currentIndex.value = selectedIndex
743
- }
744
- // 2. 处理用户一直拖拽到临界点的场景, 不会执行onEnd
745
- const { canMove, targetOffset } = checkUnCircular(eventData)
746
- if (!circularShared.value) {
747
- if (canMove) {
748
- offset.value = targetOffset
749
- preAbsolutePos.value = e[strAbso]
750
- }
716
+ // 处理用户一直拖拽到临界点的场景, 不会执行onEnd
717
+ if (!circularShared.value && !canMove(eventData)) {
751
718
  return
752
719
  }
753
720
  const { isBoundary, resetOffset } = reachBoundary(eventData)
@@ -756,21 +723,28 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
756
723
  } else {
757
724
  offset.value = moveDistance + offset.value
758
725
  }
759
- preAbsolutePos.value = e[strAbso]
726
+ preAbsolutePos.value = touchEventData[strAbso]
760
727
  })
761
- .onFinalize((e) => {
728
+ .onTouchesUp((e) => {
762
729
  'worklet'
763
730
  if (touchfinish.value) return
764
- const moveDistance = e[strAbso] - moveTranstion.value
731
+ const touchEventData = e.changedTouches[0]
732
+ const moveDistance = touchEventData[strAbso] - moveTranstion.value
765
733
  touchfinish.value = true
766
734
  const eventData = {
767
735
  translation: moveDistance
768
736
  }
737
+ if (childrenLength.value === 1) {
738
+ return handleBackInit()
739
+ }
740
+ // 用户手指按下起来, 需要计算正确的位置, 比如在滑动过程中突然按下然后起来,需要计算到正确的位置
741
+ if (!circularShared.value && !canMove(eventData)) {
742
+ return
743
+ }
769
744
  const strVelocity = moveDistance / (new Date().getTime() - moveTime.value) * 1000
770
745
  if (Math.abs(strVelocity) < longPressRatio) {
771
746
  handleLongPress()
772
747
  } else {
773
- // 如果触发了onTouchesCancelled,不会触发onUpdate不会更新offset值, 索引不会变更
774
748
  handleEnd(eventData)
775
749
  }
776
750
  })
@@ -1,6 +1,7 @@
1
- import { forwardRef, useRef, useContext, useMemo, useState, useCallback, useEffect } from 'react'
1
+ import { forwardRef, useRef, useContext, useMemo, useState } from 'react'
2
2
  import { warn, isFunction } from '@mpxjs/utils'
3
3
  import Portal from './mpx-portal/index'
4
+ import { usePreventRemove, PreventRemoveEvent } from '@react-navigation/native'
4
5
  import { getCustomEvent } from './getInnerListeners'
5
6
  import { promisify, redirectTo, navigateTo, navigateBack, reLaunch, switchTab } from '@mpxjs/api-proxy'
6
7
  import { WebView } from 'react-native-webview'
@@ -75,7 +76,6 @@ const styles = StyleSheet.create({
75
76
  borderRadius: 10
76
77
  }
77
78
  })
78
-
79
79
  const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((props, ref): JSX.Element | null => {
80
80
  const { src, bindmessage, bindload, binderror } = props
81
81
  const mpx = global.__mpx
@@ -100,8 +100,8 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
100
100
  const webViewRef = useRef<WebView>(null)
101
101
  const fristLoaded = useRef<boolean>(false)
102
102
  const isLoadError = useRef<boolean>(false)
103
+ const isNavigateBack = useRef<boolean>(false)
103
104
  const statusCode = useRef<string|number>('')
104
- const [isLoaded, setIsLoaded] = useState<boolean>(true)
105
105
  const defaultWebViewStyle = {
106
106
  position: 'absolute' as const,
107
107
  left: 0,
@@ -109,30 +109,18 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
109
109
  top: 0,
110
110
  bottom: 0
111
111
  }
112
- const canGoBack = useRef<boolean>(false)
113
- const isNavigateBack = useRef<boolean>(false)
114
112
 
115
- const beforeRemoveHandle = (e: Event) => {
116
- if (canGoBack.current && !isNavigateBack.current) {
113
+ const navigation = useNavigation()
114
+ const [isIntercept, setIsIntercept] = useState<boolean>(false)
115
+ usePreventRemove(isIntercept, (event: PreventRemoveEvent) => {
116
+ const { data } = event
117
+ if (isNavigateBack.current) {
118
+ navigation?.dispatch(data.action)
119
+ } else {
117
120
  webViewRef.current?.goBack()
118
- e.preventDefault()
119
121
  }
120
122
  isNavigateBack.current = false
121
- }
122
-
123
- const navigation = useNavigation()
124
-
125
- // useEffect(() => {
126
- // let beforeRemoveSubscription:any
127
- // if (__mpx_mode__ !== 'ios') {
128
- // beforeRemoveSubscription = navigation?.addListener?.('beforeRemove', beforeRemoveHandle)
129
- // }
130
- // return () => {
131
- // if (isFunction(beforeRemoveSubscription)) {
132
- // beforeRemoveSubscription()
133
- // }
134
- // }
135
- // }, [])
123
+ })
136
124
 
137
125
  useNodesRef<WebView, WebViewProps>(props, ref, webViewRef, {
138
126
  style: defaultWebViewStyle
@@ -183,14 +171,14 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
183
171
  }
184
172
  const _changeUrl = function (navState: WebViewNavigation) {
185
173
  if (navState.navigationType) { // navigationType这个事件在页面开始加载时和页面加载完成时都会被触发所以判断这个避免其他无效触发执行该逻辑
186
- canGoBack.current = navState.canGoBack
187
174
  currentPage.__webViewUrl = navState.url
175
+ setIsIntercept(navState.canGoBack)
188
176
  }
189
177
  }
190
178
 
191
179
  const _onLoadProgress = function (event: WebViewProgressEvent) {
192
180
  if (__mpx_mode__ !== 'ios') {
193
- canGoBack.current = event.nativeEvent.canGoBack
181
+ setIsIntercept(event.nativeEvent.canGoBack)
194
182
  }
195
183
  }
196
184
  const _message = function (res: WebViewMessageEvent) {
@@ -279,7 +267,6 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
279
267
  }
280
268
  const onLoadEndHandle = function (res: WebViewEvent) {
281
269
  fristLoaded.current = true
282
- setIsLoaded(true)
283
270
  const src = res.nativeEvent?.url
284
271
  if (isLoadError.current) {
285
272
  isLoadError.current = false
@@ -325,11 +312,6 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
325
312
  setPageLoadErr(true)
326
313
  }
327
314
  }
328
- const onLoadStart = function () {
329
- if (!fristLoaded.current) {
330
- setIsLoaded(false)
331
- }
332
- }
333
315
 
334
316
  return (
335
317
  <Portal>
@@ -342,7 +324,6 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
342
324
  )
343
325
  : (<WebView
344
326
  style={ defaultWebViewStyle }
345
- pointerEvents={ isLoaded ? 'auto' : 'none' }
346
327
  source={{ uri: src }}
347
328
  ref={webViewRef}
348
329
  javaScriptEnabled={true}
@@ -353,7 +334,6 @@ const _WebView = forwardRef<HandlerRef<WebView, WebViewProps>, WebViewProps>((pr
353
334
  onLoadEnd={onLoadEnd}
354
335
  onHttpError={onHttpError}
355
336
  onError={onError}
356
- onLoadStart={onLoadStart}
357
337
  allowsBackForwardNavigationGestures={true}
358
338
  ></WebView>)}
359
339
  </Portal>