@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.
- package/lib/dependencies/RequireExternalDependency.js +61 -0
- package/lib/file-loader.js +3 -2
- package/lib/index.js +60 -15
- package/lib/json-compiler/index.js +1 -0
- package/lib/parser.js +1 -1
- package/lib/platform/json/wx/index.js +43 -25
- package/lib/platform/template/wx/component-config/fix-component-name.js +2 -2
- package/lib/platform/template/wx/component-config/index.js +2 -0
- package/lib/platform/template/wx/component-config/movable-view.js +10 -1
- package/lib/platform/template/wx/component-config/page-container.js +19 -0
- package/lib/platform/template/wx/component-config/unsupported.js +1 -1
- package/lib/platform/template/wx/index.js +2 -1
- package/lib/react/LoadAsyncChunkModule.js +74 -0
- package/lib/react/index.js +3 -1
- package/lib/react/processJSON.js +74 -13
- package/lib/react/processScript.js +6 -6
- package/lib/react/script-helper.js +100 -41
- package/lib/runtime/components/react/context.ts +2 -12
- package/lib/runtime/components/react/dist/context.js +1 -1
- package/lib/runtime/components/react/dist/getInnerListeners.js +1 -1
- package/lib/runtime/components/react/dist/mpx-async-suspense.jsx +135 -0
- package/lib/runtime/components/react/dist/mpx-movable-area.jsx +9 -63
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +58 -301
- package/lib/runtime/components/react/dist/mpx-page-container.jsx +255 -0
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +30 -55
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +14 -28
- package/lib/runtime/components/react/dist/useAnimationHooks.js +2 -87
- package/lib/runtime/components/react/getInnerListeners.ts +1 -1
- package/lib/runtime/components/react/mpx-async-suspense.tsx +180 -0
- package/lib/runtime/components/react/mpx-movable-area.tsx +11 -98
- package/lib/runtime/components/react/mpx-movable-view.tsx +60 -350
- package/lib/runtime/components/react/mpx-page-container.tsx +394 -0
- package/lib/runtime/components/react/mpx-swiper.tsx +29 -55
- package/lib/runtime/components/react/mpx-web-view.tsx +13 -33
- package/lib/runtime/components/react/types/global.d.ts +15 -0
- package/lib/runtime/components/react/useAnimationHooks.ts +2 -85
- package/lib/runtime/optionProcessorReact.d.ts +18 -0
- package/lib/runtime/optionProcessorReact.js +30 -0
- package/lib/script-setup-compiler/index.js +27 -5
- package/lib/template-compiler/compiler.js +27 -6
- package/lib/utils/dom-tag-config.js +18 -4
- package/lib/utils/trans-async-sub-rules.js +19 -0
- package/lib/web/script-helper.js +1 -1
- package/package.json +3 -3
- package/lib/runtime/components/react/AsyncContainer.tsx +0 -189
- 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 &&
|
|
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
|
-
|
|
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
|
|
571
|
+
function canMove (eventData: EventDataType) {
|
|
579
572
|
'worklet'
|
|
580
573
|
const { translation } = eventData
|
|
581
574
|
const currentOffset = Math.abs(offset.value)
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
.
|
|
708
|
+
.onTouchesMove((e) => {
|
|
732
709
|
'worklet'
|
|
733
710
|
if (touchfinish.value) return
|
|
734
|
-
const
|
|
711
|
+
const touchEventData = e.changedTouches[0]
|
|
712
|
+
const moveDistance = touchEventData[strAbso] - preAbsolutePos.value
|
|
735
713
|
const eventData = {
|
|
736
714
|
translation: moveDistance
|
|
737
715
|
}
|
|
738
|
-
//
|
|
739
|
-
|
|
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 =
|
|
726
|
+
preAbsolutePos.value = touchEventData[strAbso]
|
|
760
727
|
})
|
|
761
|
-
.
|
|
728
|
+
.onTouchesUp((e) => {
|
|
762
729
|
'worklet'
|
|
763
730
|
if (touchfinish.value) return
|
|
764
|
-
const
|
|
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
|
|
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
|
|
116
|
-
|
|
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
|
-
|
|
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>
|