@mpxjs/webpack-plugin 2.10.6 → 2.10.7-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/dependencies/RecordPageConfigsMapDependency.js +1 -1
- package/lib/index.js +71 -51
- package/lib/parser.js +1 -1
- package/lib/platform/json/wx/index.js +0 -1
- package/lib/platform/style/wx/index.js +7 -0
- package/lib/platform/template/wx/component-config/button.js +1 -1
- package/lib/platform/template/wx/component-config/index.js +5 -1
- package/lib/platform/template/wx/component-config/input.js +1 -1
- package/lib/platform/template/wx/component-config/movable-view.js +1 -10
- package/lib/platform/template/wx/component-config/sticky-header.js +23 -0
- package/lib/platform/template/wx/component-config/sticky-section.js +23 -0
- package/lib/react/processJSON.js +2 -1
- package/lib/runtime/components/react/AsyncContainer.tsx +189 -0
- package/lib/runtime/components/react/context.ts +23 -4
- package/lib/runtime/components/react/dist/AsyncContainer.jsx +141 -0
- package/lib/runtime/components/react/dist/context.js +5 -2
- package/lib/runtime/components/react/dist/mpx-button.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-input.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-movable-area.jsx +64 -10
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +358 -98
- package/lib/runtime/components/react/dist/mpx-rich-text/index.jsx +3 -0
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +31 -15
- 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 +2 -2
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +53 -27
- package/lib/runtime/components/react/dist/mpx-view.jsx +21 -7
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +13 -13
- package/lib/runtime/components/react/dist/utils.jsx +94 -1
- package/lib/runtime/components/react/mpx-button.tsx +3 -2
- package/lib/runtime/components/react/mpx-input.tsx +1 -1
- package/lib/runtime/components/react/mpx-movable-area.tsx +99 -12
- package/lib/runtime/components/react/mpx-movable-view.tsx +413 -100
- package/lib/runtime/components/react/mpx-rich-text/index.tsx +3 -0
- package/lib/runtime/components/react/mpx-scroll-view.tsx +84 -59
- package/lib/runtime/components/react/mpx-sticky-header.tsx +181 -0
- package/lib/runtime/components/react/mpx-sticky-section.tsx +96 -0
- package/lib/runtime/components/react/mpx-swiper-item.tsx +2 -2
- package/lib/runtime/components/react/mpx-swiper.tsx +53 -25
- package/lib/runtime/components/react/mpx-view.tsx +20 -7
- package/lib/runtime/components/react/mpx-web-view.tsx +12 -12
- package/lib/runtime/components/react/utils.tsx +93 -1
- package/lib/runtime/components/web/mpx-scroll-view.vue +18 -4
- package/lib/runtime/components/web/mpx-sticky-header.vue +99 -0
- package/lib/runtime/components/web/mpx-sticky-section.vue +15 -0
- package/lib/runtime/optionProcessor.js +0 -2
- package/lib/script-setup-compiler/index.js +27 -5
- package/lib/template-compiler/bind-this.js +2 -1
- package/lib/template-compiler/compiler.js +4 -3
- package/package.json +4 -4
- package/LICENSE +0 -433
|
@@ -7,13 +7,13 @@
|
|
|
7
7
|
* ✘ damping
|
|
8
8
|
* ✘ friction
|
|
9
9
|
* ✔ disabled
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
10
|
+
* ✔ scale
|
|
11
|
+
* ✔ scale-min
|
|
12
|
+
* ✔ scale-max
|
|
13
|
+
* ✔ scale-value
|
|
14
14
|
* ✔ animation
|
|
15
15
|
* ✔ bindchange
|
|
16
|
-
*
|
|
16
|
+
* ✔ bindscale
|
|
17
17
|
* ✔ htouchmove
|
|
18
18
|
* ✔ vtouchmove
|
|
19
19
|
*/
|
|
@@ -30,8 +30,8 @@ import Animated, {
|
|
|
30
30
|
withDecay,
|
|
31
31
|
runOnJS,
|
|
32
32
|
runOnUI,
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
withSpring,
|
|
34
|
+
withTiming
|
|
35
35
|
} from 'react-native-reanimated'
|
|
36
36
|
import { collectDataset, noop } from '@mpxjs/utils'
|
|
37
37
|
|
|
@@ -43,8 +43,14 @@ interface MovableViewProps {
|
|
|
43
43
|
y?: number
|
|
44
44
|
disabled?: boolean
|
|
45
45
|
animation?: boolean
|
|
46
|
+
scale?: boolean
|
|
47
|
+
'scale-min'?: number
|
|
48
|
+
'scale-max'?: number
|
|
49
|
+
'scale-value'?: number
|
|
46
50
|
id?: string
|
|
51
|
+
changeThrottleTime?:number
|
|
47
52
|
bindchange?: (event: unknown) => void
|
|
53
|
+
bindscale?: (event: unknown) => void
|
|
48
54
|
bindtouchstart?: (event: GestureTouchEvent) => void
|
|
49
55
|
catchtouchstart?: (event: GestureTouchEvent) => void
|
|
50
56
|
bindtouchmove?: (event: GestureTouchEvent) => void
|
|
@@ -69,6 +75,7 @@ interface MovableViewProps {
|
|
|
69
75
|
'parent-font-size'?: number
|
|
70
76
|
'parent-width'?: number
|
|
71
77
|
'parent-height'?: number
|
|
78
|
+
'disable-event-passthrough'?: boolean
|
|
72
79
|
}
|
|
73
80
|
|
|
74
81
|
const styles = StyleSheet.create({
|
|
@@ -95,6 +102,10 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
95
102
|
inertia = false,
|
|
96
103
|
disabled = false,
|
|
97
104
|
animation = true,
|
|
105
|
+
scale = false,
|
|
106
|
+
'scale-min': scaleMin = 0.1,
|
|
107
|
+
'scale-max': scaleMax = 10,
|
|
108
|
+
'scale-value': scaleValue = 1,
|
|
98
109
|
'out-of-bounds': outOfBounds = false,
|
|
99
110
|
'enable-var': enableVar,
|
|
100
111
|
'external-var-context': externalVarContext,
|
|
@@ -102,9 +113,11 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
102
113
|
'parent-width': parentWidth,
|
|
103
114
|
'parent-height': parentHeight,
|
|
104
115
|
direction = 'none',
|
|
116
|
+
'disable-event-passthrough': disableEventPassthrough = false,
|
|
105
117
|
'simultaneous-handlers': originSimultaneousHandlers = [],
|
|
106
118
|
'wait-for': waitFor = [],
|
|
107
119
|
style = {},
|
|
120
|
+
changeThrottleTime = 60,
|
|
108
121
|
bindtouchstart,
|
|
109
122
|
catchtouchstart,
|
|
110
123
|
bindhtouchmove,
|
|
@@ -114,7 +127,10 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
114
127
|
catchvtouchmove,
|
|
115
128
|
catchtouchmove,
|
|
116
129
|
bindtouchend,
|
|
117
|
-
catchtouchend
|
|
130
|
+
catchtouchend,
|
|
131
|
+
bindscale,
|
|
132
|
+
bindchange,
|
|
133
|
+
onLayout: propsOnLayout
|
|
118
134
|
} = props
|
|
119
135
|
|
|
120
136
|
const {
|
|
@@ -124,7 +140,7 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
124
140
|
varContextRef,
|
|
125
141
|
setWidth,
|
|
126
142
|
setHeight
|
|
127
|
-
} = useTransformStyle(Object.assign({},
|
|
143
|
+
} = useTransformStyle(Object.assign({}, styles.container, style), { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight })
|
|
128
144
|
|
|
129
145
|
const navigation = useNavigation()
|
|
130
146
|
|
|
@@ -135,11 +151,14 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
135
151
|
|
|
136
152
|
const offsetX = useSharedValue(x)
|
|
137
153
|
const offsetY = useSharedValue(y)
|
|
154
|
+
const currentScale = useSharedValue(1)
|
|
155
|
+
const layoutValue = useSharedValue<any>({})
|
|
138
156
|
|
|
139
157
|
const startPosition = useSharedValue({
|
|
140
158
|
x: 0,
|
|
141
159
|
y: 0
|
|
142
160
|
})
|
|
161
|
+
|
|
143
162
|
const draggableXRange = useSharedValue<[min: number, max: number]>([0, 0])
|
|
144
163
|
const draggableYRange = useSharedValue<[min: number, max: number]>([0, 0])
|
|
145
164
|
const isMoving = useSharedValue(false)
|
|
@@ -148,6 +167,7 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
148
167
|
const isFirstTouch = useSharedValue(true)
|
|
149
168
|
const touchEvent = useSharedValue<string>('')
|
|
150
169
|
const initialViewPosition = useSharedValue({ x: x || 0, y: y || 0 })
|
|
170
|
+
const lastChangeTime = useSharedValue(0)
|
|
151
171
|
|
|
152
172
|
const MovableAreaLayout = useContext(MovableAreaContext)
|
|
153
173
|
|
|
@@ -195,6 +215,51 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
195
215
|
)
|
|
196
216
|
}, [])
|
|
197
217
|
|
|
218
|
+
const handleTriggerScale = useCallback(({ x, y, scale }: { x: number; y: number; scale: number }) => {
|
|
219
|
+
const { bindscale } = propsRef.current
|
|
220
|
+
if (!bindscale) return
|
|
221
|
+
bindscale(
|
|
222
|
+
getCustomEvent('scale', {}, {
|
|
223
|
+
detail: {
|
|
224
|
+
x,
|
|
225
|
+
y,
|
|
226
|
+
scale
|
|
227
|
+
},
|
|
228
|
+
layoutRef
|
|
229
|
+
}, propsRef.current)
|
|
230
|
+
)
|
|
231
|
+
}, [])
|
|
232
|
+
|
|
233
|
+
const checkBoundaryPosition = useCallback(({ positionX, positionY }: { positionX: number; positionY: number }) => {
|
|
234
|
+
'worklet'
|
|
235
|
+
let x = positionX
|
|
236
|
+
let y = positionY
|
|
237
|
+
// 计算边界限制
|
|
238
|
+
if (x > draggableXRange.value[1]) {
|
|
239
|
+
x = draggableXRange.value[1]
|
|
240
|
+
} else if (x < draggableXRange.value[0]) {
|
|
241
|
+
x = draggableXRange.value[0]
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (y > draggableYRange.value[1]) {
|
|
245
|
+
y = draggableYRange.value[1]
|
|
246
|
+
} else if (y < draggableYRange.value[0]) {
|
|
247
|
+
y = draggableYRange.value[0]
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return { x, y }
|
|
251
|
+
}, [])
|
|
252
|
+
|
|
253
|
+
// 节流版本的 change 事件触发
|
|
254
|
+
const handleTriggerChangeThrottled = useCallback(({ x, y, type }: { x: number; y: number; type?: string }) => {
|
|
255
|
+
'worklet'
|
|
256
|
+
const now = Date.now()
|
|
257
|
+
if (now - lastChangeTime.value >= changeThrottleTime) {
|
|
258
|
+
lastChangeTime.value = now
|
|
259
|
+
runOnJS(handleTriggerChange)({ x, y, type })
|
|
260
|
+
}
|
|
261
|
+
}, [changeThrottleTime])
|
|
262
|
+
|
|
198
263
|
useEffect(() => {
|
|
199
264
|
runOnUI(() => {
|
|
200
265
|
if (offsetX.value !== x || offsetY.value !== y) {
|
|
@@ -215,7 +280,7 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
215
280
|
})
|
|
216
281
|
: newY
|
|
217
282
|
}
|
|
218
|
-
if (
|
|
283
|
+
if (bindchange) {
|
|
219
284
|
runOnJS(handleTriggerChange)({
|
|
220
285
|
x: newX,
|
|
221
286
|
y: newY,
|
|
@@ -226,13 +291,224 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
226
291
|
})()
|
|
227
292
|
}, [x, y])
|
|
228
293
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
294
|
+
// 提取通用的缩放边界计算函数
|
|
295
|
+
const calculateScaleBoundaryPosition = useCallback(({
|
|
296
|
+
currentOffsetX,
|
|
297
|
+
currentOffsetY,
|
|
298
|
+
newScale,
|
|
299
|
+
width,
|
|
300
|
+
height
|
|
301
|
+
}: {
|
|
302
|
+
currentOffsetX: number
|
|
303
|
+
currentOffsetY: number
|
|
304
|
+
newScale: number
|
|
305
|
+
width: number
|
|
306
|
+
height: number
|
|
307
|
+
}) => {
|
|
308
|
+
'worklet'
|
|
309
|
+
const prevScale = currentScale.value
|
|
310
|
+
|
|
311
|
+
// 计算元素当前中心点(在屏幕上的位置)
|
|
312
|
+
const currentCenterX = currentOffsetX + (width * prevScale) / 2
|
|
313
|
+
const currentCenterY = currentOffsetY + (height * prevScale) / 2
|
|
314
|
+
|
|
315
|
+
// 实现中心缩放:保持元素中心点不变
|
|
316
|
+
// 计算缩放后为了保持中心点不变需要的新offset位置
|
|
317
|
+
let newOffsetX = currentCenterX - (width * newScale) / 2
|
|
318
|
+
let newOffsetY = currentCenterY - (height * newScale) / 2
|
|
319
|
+
|
|
320
|
+
// 缩放过程中实时边界检测
|
|
321
|
+
// 计算新的边界范围
|
|
322
|
+
const top = (style.position === 'absolute' && style.top) || 0
|
|
323
|
+
const left = (style.position === 'absolute' && style.left) || 0
|
|
324
|
+
const scaledWidth = width * newScale
|
|
325
|
+
const scaledHeight = height * newScale
|
|
326
|
+
|
|
327
|
+
// 计算新缩放值下的边界限制
|
|
328
|
+
const maxOffsetY = MovableAreaLayout.height - scaledHeight - top
|
|
329
|
+
const maxOffsetX = MovableAreaLayout.width - scaledWidth - left
|
|
330
|
+
|
|
331
|
+
let xMin, xMax, yMin, yMax
|
|
332
|
+
|
|
333
|
+
if (MovableAreaLayout.width < scaledWidth) {
|
|
334
|
+
xMin = maxOffsetX
|
|
335
|
+
xMax = -left
|
|
336
|
+
} else {
|
|
337
|
+
xMin = -left
|
|
338
|
+
xMax = maxOffsetX < 0 ? -left : maxOffsetX
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (MovableAreaLayout.height < scaledHeight) {
|
|
342
|
+
yMin = maxOffsetY
|
|
343
|
+
yMax = -top
|
|
344
|
+
} else {
|
|
345
|
+
yMin = -top
|
|
346
|
+
yMax = maxOffsetY < 0 ? -top : maxOffsetY
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// 应用边界限制
|
|
350
|
+
if (newOffsetX > xMax) {
|
|
351
|
+
newOffsetX = xMax
|
|
352
|
+
} else if (newOffsetX < xMin) {
|
|
353
|
+
newOffsetX = xMin
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
if (newOffsetY > yMax) {
|
|
357
|
+
newOffsetY = yMax
|
|
358
|
+
} else if (newOffsetY < yMin) {
|
|
359
|
+
newOffsetY = yMin
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
return { x: newOffsetX, y: newOffsetY }
|
|
363
|
+
}, [MovableAreaLayout.height, MovableAreaLayout.width, style.position, style.top, style.left])
|
|
364
|
+
|
|
365
|
+
// 提取通用的缩放处理函数
|
|
366
|
+
const handleScaleUpdate = useCallback((scaleInfo: { scale: number }) => {
|
|
367
|
+
'worklet'
|
|
368
|
+
if (disabled) return
|
|
369
|
+
|
|
370
|
+
// 判断缩放方向并计算新的缩放值
|
|
371
|
+
const isZoomingIn = scaleInfo.scale > 1
|
|
372
|
+
const isZoomingOut = scaleInfo.scale < 1
|
|
373
|
+
|
|
374
|
+
let newScale
|
|
375
|
+
if (isZoomingIn) {
|
|
376
|
+
// 放大:增加缩放值
|
|
377
|
+
newScale = currentScale.value + (scaleInfo.scale - 1) * 0.5
|
|
378
|
+
} else if (isZoomingOut) {
|
|
379
|
+
// 缩小:减少缩放值
|
|
380
|
+
newScale = currentScale.value - (1 - scaleInfo.scale) * 0.5
|
|
381
|
+
} else {
|
|
382
|
+
// 没有缩放变化
|
|
383
|
+
newScale = currentScale.value
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// 限制缩放值在 scaleMin 和 scaleMax 之间
|
|
387
|
+
newScale = Math.max(scaleMin, Math.min(scaleMax, newScale))
|
|
388
|
+
|
|
389
|
+
// 只有当缩放值真正改变时才调整位置
|
|
390
|
+
if (Math.abs(newScale - currentScale.value) > 0.01) {
|
|
391
|
+
// 获取元素尺寸
|
|
392
|
+
const { width = 0, height = 0 } = layoutValue.value
|
|
393
|
+
|
|
394
|
+
if (width > 0 && height > 0) {
|
|
395
|
+
// 使用通用的边界计算函数
|
|
396
|
+
const { x: newOffsetX, y: newOffsetY } = calculateScaleBoundaryPosition({
|
|
397
|
+
currentOffsetX: offsetX.value,
|
|
398
|
+
currentOffsetY: offsetY.value,
|
|
399
|
+
newScale,
|
|
400
|
+
width,
|
|
401
|
+
height
|
|
402
|
+
})
|
|
403
|
+
|
|
404
|
+
offsetX.value = newOffsetX
|
|
405
|
+
offsetY.value = newOffsetY
|
|
406
|
+
|
|
407
|
+
// 更新缩放值
|
|
408
|
+
currentScale.value = newScale
|
|
409
|
+
}
|
|
410
|
+
} else {
|
|
411
|
+
currentScale.value = newScale
|
|
233
412
|
}
|
|
413
|
+
|
|
414
|
+
if (bindscale) {
|
|
415
|
+
runOnJS(handleTriggerScale)({
|
|
416
|
+
x: offsetX.value,
|
|
417
|
+
y: offsetY.value,
|
|
418
|
+
scale: newScale
|
|
419
|
+
})
|
|
420
|
+
}
|
|
421
|
+
}, [disabled, scaleMin, scaleMax, bindscale, handleTriggerScale, calculateScaleBoundaryPosition, style.position, style.top, style.left, MovableAreaLayout.height, MovableAreaLayout.width])
|
|
422
|
+
|
|
423
|
+
useEffect(() => {
|
|
424
|
+
runOnUI(() => {
|
|
425
|
+
if (currentScale.value !== scaleValue) {
|
|
426
|
+
// 限制缩放值在 scaleMin 和 scaleMax 之间
|
|
427
|
+
const clampedScale = Math.max(scaleMin, Math.min(scaleMax, scaleValue))
|
|
428
|
+
|
|
429
|
+
// 实现中心缩放的位置补偿
|
|
430
|
+
const { width = 0, height = 0 } = layoutValue.value
|
|
431
|
+
if (width > 0 && height > 0) {
|
|
432
|
+
// 使用通用的边界计算函数
|
|
433
|
+
const { x: newOffsetX, y: newOffsetY } = calculateScaleBoundaryPosition({
|
|
434
|
+
currentOffsetX: offsetX.value,
|
|
435
|
+
currentOffsetY: offsetY.value,
|
|
436
|
+
newScale: clampedScale,
|
|
437
|
+
width,
|
|
438
|
+
height
|
|
439
|
+
})
|
|
440
|
+
|
|
441
|
+
// 同时更新缩放值和位置
|
|
442
|
+
if (animation) {
|
|
443
|
+
currentScale.value = withTiming(clampedScale, {
|
|
444
|
+
duration: 1000
|
|
445
|
+
}, () => {
|
|
446
|
+
handleRestBoundaryAndCheck()
|
|
447
|
+
})
|
|
448
|
+
offsetX.value = withTiming(newOffsetX, { duration: 1000 })
|
|
449
|
+
offsetY.value = withTiming(newOffsetY, { duration: 1000 })
|
|
450
|
+
} else {
|
|
451
|
+
currentScale.value = clampedScale
|
|
452
|
+
offsetX.value = newOffsetX
|
|
453
|
+
offsetY.value = newOffsetY
|
|
454
|
+
handleRestBoundaryAndCheck()
|
|
455
|
+
}
|
|
456
|
+
} else {
|
|
457
|
+
// 如果还没有尺寸信息,只更新缩放值
|
|
458
|
+
if (animation) {
|
|
459
|
+
currentScale.value = withTiming(clampedScale, {
|
|
460
|
+
duration: 1000
|
|
461
|
+
}, () => {
|
|
462
|
+
handleRestBoundaryAndCheck()
|
|
463
|
+
})
|
|
464
|
+
} else {
|
|
465
|
+
currentScale.value = clampedScale
|
|
466
|
+
handleRestBoundaryAndCheck()
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (bindscale) {
|
|
471
|
+
runOnJS(handleTriggerScale)({
|
|
472
|
+
x: offsetX.value,
|
|
473
|
+
y: offsetY.value,
|
|
474
|
+
scale: clampedScale
|
|
475
|
+
})
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
})()
|
|
479
|
+
}, [scaleValue, scaleMin, scaleMax, animation])
|
|
480
|
+
|
|
481
|
+
useEffect(() => {
|
|
482
|
+
runOnUI(handleRestBoundaryAndCheck)()
|
|
234
483
|
}, [MovableAreaLayout.height, MovableAreaLayout.width])
|
|
235
484
|
|
|
485
|
+
// 生成唯一 ID
|
|
486
|
+
const viewId = useMemo(() => `movable-view-${Date.now()}-${Math.random()}`, [])
|
|
487
|
+
|
|
488
|
+
// 注册到 MovableArea(如果启用了 scale-area)
|
|
489
|
+
useEffect(() => {
|
|
490
|
+
if (MovableAreaLayout.scaleArea && MovableAreaLayout.registerMovableView && MovableAreaLayout.unregisterMovableView) {
|
|
491
|
+
const handleAreaScale = (scaleInfo: { scale: number }) => {
|
|
492
|
+
'worklet'
|
|
493
|
+
handleScaleUpdate({ scale: scaleInfo.scale })
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
const handleAreaScaleEnd = () => {
|
|
497
|
+
'worklet'
|
|
498
|
+
handleRestBoundaryAndCheck()
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
MovableAreaLayout.registerMovableView?.(viewId, {
|
|
502
|
+
onScale: scale ? handleAreaScale : noop,
|
|
503
|
+
onScaleEnd: scale ? handleAreaScaleEnd : noop
|
|
504
|
+
})
|
|
505
|
+
|
|
506
|
+
return () => {
|
|
507
|
+
MovableAreaLayout.unregisterMovableView?.(viewId)
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
}, [MovableAreaLayout.scaleArea, viewId, scale, handleScaleUpdate])
|
|
511
|
+
|
|
236
512
|
const getTouchSource = useCallback((offsetX: number, offsetY: number) => {
|
|
237
513
|
const hasOverBoundary = offsetX < draggableXRange.value[0] || offsetX > draggableXRange.value[1] ||
|
|
238
514
|
offsetY < draggableYRange.value[0] || offsetY > draggableYRange.value[1]
|
|
@@ -255,66 +531,50 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
255
531
|
}, [])
|
|
256
532
|
|
|
257
533
|
const setBoundary = useCallback(({ width, height }: { width: number; height: number }) => {
|
|
534
|
+
'worklet'
|
|
258
535
|
const top = (style.position === 'absolute' && style.top) || 0
|
|
259
536
|
const left = (style.position === 'absolute' && style.left) || 0
|
|
260
537
|
|
|
261
|
-
|
|
262
|
-
const
|
|
538
|
+
// 使用左上角缩放,计算offset位置的边界范围
|
|
539
|
+
const currentScaleVal = currentScale.value
|
|
540
|
+
const scaledWidth = (width || 0) * currentScaleVal
|
|
541
|
+
const scaledHeight = (height || 0) * currentScaleVal
|
|
263
542
|
|
|
264
|
-
|
|
265
|
-
const
|
|
543
|
+
// offset位置的边界:左上角可以移动的范围
|
|
544
|
+
const maxOffsetY = MovableAreaLayout.height - scaledHeight - top
|
|
545
|
+
const maxOffsetX = MovableAreaLayout.width - scaledWidth - left
|
|
266
546
|
|
|
267
547
|
let xRange: [min: number, max: number]
|
|
268
548
|
let yRange: [min: number, max: number]
|
|
269
549
|
|
|
270
550
|
if (MovableAreaLayout.width < scaledWidth) {
|
|
271
|
-
xRange = [
|
|
551
|
+
xRange = [maxOffsetX, -left]
|
|
272
552
|
} else {
|
|
273
|
-
xRange = [
|
|
553
|
+
xRange = [-left, maxOffsetX < 0 ? -left : maxOffsetX]
|
|
274
554
|
}
|
|
275
555
|
|
|
276
556
|
if (MovableAreaLayout.height < scaledHeight) {
|
|
277
|
-
yRange = [
|
|
557
|
+
yRange = [maxOffsetY, -top]
|
|
278
558
|
} else {
|
|
279
|
-
yRange = [
|
|
559
|
+
yRange = [-top, maxOffsetY < 0 ? -top : maxOffsetY]
|
|
280
560
|
}
|
|
561
|
+
|
|
281
562
|
draggableXRange.value = xRange
|
|
282
563
|
draggableYRange.value = yRange
|
|
283
564
|
}, [MovableAreaLayout.height, MovableAreaLayout.width, style.position, style.top, style.left])
|
|
284
565
|
|
|
285
|
-
const
|
|
566
|
+
const resetBoundaryAndCheck = ({ width, height }: { width: number; height: number }) => {
|
|
286
567
|
'worklet'
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
x = draggableXRange.value[0]
|
|
568
|
+
setBoundary({ width, height })
|
|
569
|
+
const positionX = offsetX.value
|
|
570
|
+
const positionY = offsetY.value
|
|
571
|
+
const { x: newX, y: newY } = checkBoundaryPosition({ positionX, positionY })
|
|
572
|
+
if (positionX !== newX) {
|
|
573
|
+
offsetX.value = newX
|
|
294
574
|
}
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
y = draggableYRange.value[1]
|
|
298
|
-
} else if (y < draggableYRange.value[0]) {
|
|
299
|
-
y = draggableYRange.value[0]
|
|
575
|
+
if (positionY !== newY) {
|
|
576
|
+
offsetY.value = newY
|
|
300
577
|
}
|
|
301
|
-
|
|
302
|
-
return { x, y }
|
|
303
|
-
}, [])
|
|
304
|
-
|
|
305
|
-
const resetBoundaryAndCheck = ({ width, height }: { width: number; height: number }) => {
|
|
306
|
-
setBoundary({ width, height })
|
|
307
|
-
runOnUI(() => {
|
|
308
|
-
const positionX = offsetX.value
|
|
309
|
-
const positionY = offsetY.value
|
|
310
|
-
const { x: newX, y: newY } = checkBoundaryPosition({ positionX, positionY })
|
|
311
|
-
if (positionX !== newX) {
|
|
312
|
-
offsetX.value = newX
|
|
313
|
-
}
|
|
314
|
-
if (positionY !== newY) {
|
|
315
|
-
offsetY.value = newY
|
|
316
|
-
}
|
|
317
|
-
})()
|
|
318
578
|
}
|
|
319
579
|
|
|
320
580
|
const onLayout = (e: LayoutChangeEvent) => {
|
|
@@ -327,14 +587,19 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
327
587
|
nodeRef.current?.measure((x: number, y: number, width: number, height: number) => {
|
|
328
588
|
const { y: navigationY = 0 } = navigation?.layout || {}
|
|
329
589
|
layoutRef.current = { x, y: y - navigationY, width, height, offsetLeft: 0, offsetTop: 0 }
|
|
330
|
-
|
|
590
|
+
// 同时更新 layoutValue,供缩放逻辑使用
|
|
591
|
+
runOnUI(() => {
|
|
592
|
+
layoutValue.value = { width, height }
|
|
593
|
+
resetBoundaryAndCheck({ width: width, height: height })
|
|
594
|
+
})()
|
|
331
595
|
})
|
|
332
|
-
|
|
596
|
+
propsOnLayout && propsOnLayout(e)
|
|
333
597
|
}
|
|
334
598
|
|
|
335
599
|
const extendEvent = useCallback((e: any, type: 'start' | 'move' | 'end') => {
|
|
336
600
|
const { y: navigationY = 0 } = navigation?.layout || {}
|
|
337
601
|
const touchArr = [e.changedTouches, e.allTouches]
|
|
602
|
+
const currentProps = propsRef.current
|
|
338
603
|
touchArr.forEach(touches => {
|
|
339
604
|
touches && touches.forEach((item: { absoluteX: number; absoluteY: number; pageX: number; pageY: number; clientX: number; clientY: number }) => {
|
|
340
605
|
item.pageX = item.absoluteX
|
|
@@ -346,8 +611,8 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
346
611
|
Object.assign(e, {
|
|
347
612
|
touches: type === 'end' ? [] : e.allTouches,
|
|
348
613
|
currentTarget: {
|
|
349
|
-
id:
|
|
350
|
-
dataset: collectDataset(
|
|
614
|
+
id: currentProps.id || '',
|
|
615
|
+
dataset: collectDataset(currentProps),
|
|
351
616
|
offsetLeft: 0,
|
|
352
617
|
offsetTop: 0
|
|
353
618
|
},
|
|
@@ -356,12 +621,14 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
356
621
|
}, [])
|
|
357
622
|
|
|
358
623
|
const triggerStartOnJS = ({ e }: { e: GestureTouchEvent }) => {
|
|
624
|
+
const { bindtouchstart, catchtouchstart } = propsRef.current
|
|
359
625
|
extendEvent(e, 'start')
|
|
360
626
|
bindtouchstart && bindtouchstart(e)
|
|
361
627
|
catchtouchstart && catchtouchstart(e)
|
|
362
628
|
}
|
|
363
629
|
|
|
364
630
|
const triggerMoveOnJS = ({ e, hasTouchmove, hasCatchTouchmove, touchEvent }: { e: GestureTouchEvent; hasTouchmove: boolean; hasCatchTouchmove: boolean; touchEvent: string }) => {
|
|
631
|
+
const { bindhtouchmove, bindvtouchmove, bindtouchmove, catchhtouchmove, catchvtouchmove, catchtouchmove } = propsRef.current
|
|
365
632
|
extendEvent(e, 'move')
|
|
366
633
|
if (hasTouchmove) {
|
|
367
634
|
if (touchEvent === 'htouchmove') {
|
|
@@ -383,11 +650,20 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
383
650
|
}
|
|
384
651
|
|
|
385
652
|
const triggerEndOnJS = ({ e }: { e: GestureTouchEvent }) => {
|
|
653
|
+
const { bindtouchend, catchtouchend } = propsRef.current
|
|
386
654
|
extendEvent(e, 'end')
|
|
387
655
|
bindtouchend && bindtouchend(e)
|
|
388
656
|
catchtouchend && catchtouchend(e)
|
|
389
657
|
}
|
|
390
658
|
|
|
659
|
+
const handleRestBoundaryAndCheck = () => {
|
|
660
|
+
'worklet'
|
|
661
|
+
const { width, height } = layoutValue.value
|
|
662
|
+
if (width && height) {
|
|
663
|
+
resetBoundaryAndCheck({ width, height })
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
391
667
|
const gesture = useMemo(() => {
|
|
392
668
|
const handleTriggerMove = (e: GestureTouchEvent) => {
|
|
393
669
|
'worklet'
|
|
@@ -404,6 +680,8 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
404
680
|
}
|
|
405
681
|
|
|
406
682
|
const gesturePan = Gesture.Pan()
|
|
683
|
+
.minPointers(1)
|
|
684
|
+
.maxPointers(1)
|
|
407
685
|
.onTouchesDown((e: GestureTouchEvent) => {
|
|
408
686
|
'worklet'
|
|
409
687
|
const changedTouches = e.changedTouches[0] || { x: 0, y: 0 }
|
|
@@ -454,8 +732,9 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
454
732
|
offsetY.value = newY
|
|
455
733
|
}
|
|
456
734
|
}
|
|
457
|
-
if (
|
|
458
|
-
runOnJS
|
|
735
|
+
if (bindchange) {
|
|
736
|
+
// 使用节流版本减少 runOnJS 调用
|
|
737
|
+
handleTriggerChangeThrottled({
|
|
459
738
|
x: offsetX.value,
|
|
460
739
|
y: offsetY.value
|
|
461
740
|
})
|
|
@@ -493,55 +772,57 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
493
772
|
})
|
|
494
773
|
: y
|
|
495
774
|
}
|
|
496
|
-
if (
|
|
775
|
+
if (bindchange) {
|
|
497
776
|
runOnJS(handleTriggerChange)({
|
|
498
777
|
x,
|
|
499
778
|
y
|
|
500
779
|
})
|
|
501
780
|
}
|
|
502
781
|
}
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
}
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
}
|
|
782
|
+
} else if (inertia) {
|
|
783
|
+
// 惯性处理
|
|
784
|
+
if (direction === 'horizontal' || direction === 'all') {
|
|
785
|
+
xInertialMotion.value = true
|
|
786
|
+
offsetX.value = withDecay({
|
|
787
|
+
velocity: e.velocityX / 10,
|
|
788
|
+
rubberBandEffect: outOfBounds,
|
|
789
|
+
clamp: draggableXRange.value
|
|
790
|
+
}, () => {
|
|
791
|
+
xInertialMotion.value = false
|
|
792
|
+
if (bindchange) {
|
|
793
|
+
runOnJS(handleTriggerChange)({
|
|
794
|
+
x: offsetX.value,
|
|
795
|
+
y: offsetY.value
|
|
796
|
+
})
|
|
797
|
+
}
|
|
798
|
+
})
|
|
799
|
+
}
|
|
800
|
+
if (direction === 'vertical' || direction === 'all') {
|
|
801
|
+
yInertialMotion.value = true
|
|
802
|
+
offsetY.value = withDecay({
|
|
803
|
+
velocity: e.velocityY / 10,
|
|
804
|
+
rubberBandEffect: outOfBounds,
|
|
805
|
+
clamp: draggableYRange.value
|
|
806
|
+
}, () => {
|
|
807
|
+
yInertialMotion.value = false
|
|
808
|
+
if (bindchange) {
|
|
809
|
+
runOnJS(handleTriggerChange)({
|
|
810
|
+
x: offsetX.value,
|
|
811
|
+
y: offsetY.value
|
|
812
|
+
})
|
|
813
|
+
}
|
|
814
|
+
})
|
|
815
|
+
}
|
|
537
816
|
}
|
|
538
817
|
})
|
|
539
818
|
.withRef(movableGestureRef)
|
|
540
819
|
|
|
541
|
-
if (
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
820
|
+
if (!disableEventPassthrough) {
|
|
821
|
+
if (direction === 'horizontal') {
|
|
822
|
+
gesturePan.activeOffsetX([-5, 5]).failOffsetY([-5, 5])
|
|
823
|
+
} else if (direction === 'vertical') {
|
|
824
|
+
gesturePan.activeOffsetY([-5, 5]).failOffsetX([-5, 5])
|
|
825
|
+
}
|
|
545
826
|
}
|
|
546
827
|
|
|
547
828
|
if (simultaneousHandlers && simultaneousHandlers.length) {
|
|
@@ -551,14 +832,46 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
551
832
|
if (waitForHandlers && waitForHandlers.length) {
|
|
552
833
|
gesturePan.requireExternalGestureToFail(...waitForHandlers)
|
|
553
834
|
}
|
|
835
|
+
|
|
836
|
+
// 添加缩放手势支持
|
|
837
|
+
if (scale && !MovableAreaLayout.scaleArea) {
|
|
838
|
+
const gesturePinch = Gesture.Pinch()
|
|
839
|
+
.onUpdate((e: any) => {
|
|
840
|
+
'worklet'
|
|
841
|
+
handleScaleUpdate({ scale: e.scale })
|
|
842
|
+
})
|
|
843
|
+
.onEnd((e: any) => {
|
|
844
|
+
'worklet'
|
|
845
|
+
if (disabled) return
|
|
846
|
+
// 确保最终缩放值在有效范围内
|
|
847
|
+
const finalScale = Math.max(scaleMin, Math.min(scaleMax, currentScale.value))
|
|
848
|
+
if (finalScale !== currentScale.value) {
|
|
849
|
+
currentScale.value = finalScale
|
|
850
|
+
if (bindscale) {
|
|
851
|
+
runOnJS(handleTriggerScale)({
|
|
852
|
+
x: offsetX.value,
|
|
853
|
+
y: offsetY.value,
|
|
854
|
+
scale: finalScale
|
|
855
|
+
})
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
// 缩放结束后重新检查边界
|
|
859
|
+
handleRestBoundaryAndCheck()
|
|
860
|
+
})
|
|
861
|
+
|
|
862
|
+
// 根据手指数量自动区分手势:一指移动,两指缩放
|
|
863
|
+
return Gesture.Exclusive(gesturePan, gesturePinch)
|
|
864
|
+
}
|
|
865
|
+
|
|
554
866
|
return gesturePan
|
|
555
|
-
}, [disabled, direction, inertia, outOfBounds, gestureSwitch.current])
|
|
867
|
+
}, [disabled, direction, inertia, outOfBounds, scale, scaleMin, scaleMax, animation, gestureSwitch.current, handleScaleUpdate, MovableAreaLayout.scaleArea])
|
|
556
868
|
|
|
557
869
|
const animatedStyles = useAnimatedStyle(() => {
|
|
558
870
|
return {
|
|
559
871
|
transform: [
|
|
560
872
|
{ translateX: offsetX.value },
|
|
561
|
-
{ translateY: offsetY.value }
|
|
873
|
+
{ translateY: offsetY.value },
|
|
874
|
+
{ scale: currentScale.value }
|
|
562
875
|
]
|
|
563
876
|
}
|
|
564
877
|
})
|
|
@@ -605,7 +918,7 @@ const _MovableView = forwardRef<HandlerRef<View, MovableViewProps>, MovableViewP
|
|
|
605
918
|
{
|
|
606
919
|
ref: nodeRef,
|
|
607
920
|
onLayout: onLayout,
|
|
608
|
-
style: [innerStyle, animatedStyles, layoutStyle]
|
|
921
|
+
style: [{ transformOrigin: 'top left' }, innerStyle, animatedStyles, layoutStyle]
|
|
609
922
|
},
|
|
610
923
|
rewriteCatchEvent()
|
|
611
924
|
)
|