Skip to content

Commit 1e04d2c

Browse files
author
luyongfang
committed
swiper优化备份
1 parent f5da38d commit 1e04d2c

1 file changed

Lines changed: 100 additions & 2 deletions

File tree

packages/webpack-plugin/lib/runtime/components/react/mpx-swiper.tsx

Lines changed: 100 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ type EventDataType = {
4242
type EventEndType = {
4343
transdir: number
4444
}
45+
// bindtransition回调的参数
46+
type EventTransition = {
47+
dx: number
48+
dy: number
49+
}
4550

4651
interface SwiperProps {
4752
children?: ReactNode
@@ -78,6 +83,8 @@ interface SwiperProps {
7883
'simultaneous-handlers'?: Array<GestureHandler>
7984
disableGesture?: boolean
8085
bindchange?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void
86+
bindtransition?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void
87+
bindanimationfinish?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void
8188
}
8289

8390
/**
@@ -158,7 +165,9 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
158165
circular = false,
159166
disableGesture = false,
160167
current: propCurrent = 0,
161-
bindchange
168+
bindchange,
169+
bindtransition,
170+
bindanimationfinish
162171
} = props
163172

164173
const dotCommonStyle = {
@@ -238,6 +247,8 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
238247
const intervalTimer = props.interval || 500
239248
// 记录是否首次,首次不能触发bindchange回调
240249
const isFirstRef = useRef(true)
250+
// 记录每次过渡动画起点item的offset坐标,用于bindtransition计算
251+
const transitionSourceOffset = useSharedValue(0)
241252

242253
const simultaneousHandlers = flatGesture(originSimultaneousHandlers)
243254
const waitForHandlers = flatGesture(waitFor)
@@ -395,6 +406,8 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
395406
const { loop, pauseLoop, resumeLoop } = useMemo(() => {
396407
function createAutoPlay () {
397408
if (!step.value) return
409+
// 记录起点:circular 减去 preMargin
410+
transitionSourceOffset.value = circularShared.value ? -(currentIndex.value + patchElmNumShared.value) * step.value + preMarginShared.value : -currentIndex.value * step.value
398411
let targetOffset = 0
399412
let nextIndex = currentIndex.value
400413
if (!circularShared.value) {
@@ -412,6 +425,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
412425
}, () => {
413426
currentIndex.value = nextIndex
414427
runOnJS(runOnJSCallback)('loop')
428+
bindanimationfinish && runOnJS(runOnJSCallback)('handleAnimationfinish', nextIndex)
415429
})
416430
} else {
417431
// 默认向右, 向下
@@ -427,6 +441,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
427441
offset.value = initOffset
428442
currentIndex.value = nextIndex
429443
runOnJS(runOnJSCallback)('loop')
444+
bindanimationfinish && runOnJS(runOnJSCallback)('handleAnimationfinish', nextIndex)
430445
})
431446
} else {
432447
nextIndex = currentIndex.value + 1
@@ -438,6 +453,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
438453
}, () => {
439454
currentIndex.value = nextIndex
440455
runOnJS(runOnJSCallback)('loop')
456+
bindanimationfinish && runOnJS(runOnJSCallback)('handleAnimationfinish', nextIndex)
441457
})
442458
}
443459
}
@@ -470,11 +486,23 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
470486
bindchange && bindchange(eventData)
471487
}
472488

489+
function handleTransition (transData: EventTransition) {
490+
const eventData = getCustomEvent('change', {}, { detail: transData, layoutRef: layoutRef })
491+
bindtransition && bindtransition(eventData)
492+
}
493+
494+
function handleAnimationfinish (current: number) {
495+
const eventData = getCustomEvent('change', {}, { detail: { current, source: 'touch' }, layoutRef: layoutRef })
496+
bindanimationfinish && bindanimationfinish(eventData)
497+
}
498+
473499
const runOnJSCallbackRef = useRef({
474500
loop,
475501
pauseLoop,
476502
resumeLoop,
477-
handleSwiperChange
503+
handleSwiperChange,
504+
handleTransition,
505+
handleAnimationfinish
478506
})
479507
const runOnJSCallback = useRunOnJSCallback(runOnJSCallbackRef)
480508

@@ -495,11 +523,14 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
495523
if (targetOffset !== offset.value) {
496524
// 内部基于props.current!==currentIndex.value决定是否使用动画及更新currentIndex.value
497525
if (propCurrent !== undefined && propCurrent !== currentIndex.value) {
526+
// 记录起点(变更前的当前 item 坐标)
527+
transitionSourceOffset.value = circularShared.value ? -(currentIndex.value + patchElmNumShared.value) * stepValue + preMarginShared.value : -currentIndex.value * stepValue
498528
offset.value = withTiming(targetOffset, {
499529
duration: easeDuration,
500530
easing: easeMap[easeingFunc]
501531
}, () => {
502532
currentIndex.value = propCurrent
533+
bindanimationfinish && runOnJS(runOnJSCallback)('handleAnimationfinish', propCurrent)
503534
})
504535
} else {
505536
offset.value = targetOffset
@@ -513,6 +544,49 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
513544
pauseLoop()
514545
}
515546
}
547+
// AutoPlay的优化,基于offset变化,提前更新currentIndex
548+
useAnimatedReaction(
549+
() => offset.value,
550+
(newOffset) => {
551+
// 只在自动播放动画过程中(非手势)处理
552+
if (!touchfinish.value) return
553+
if (!step.value || childrenLength.value <= 1) return
554+
555+
// 与 computeHalf 逻辑对齐:计算当前 offset 距离当前 index "home位置" 是否超过一半
556+
let homeOffset = (currentIndex.value + patchElmNumShared.value) * step.value
557+
if (circularShared.value) {
558+
homeOffset -= preMarginShared.value
559+
}
560+
const diff = homeOffset - Math.abs(newOffset)
561+
if (Math.abs(diff) > step.value / 2) {
562+
// 超过一半,提前更新 currentIndex
563+
// diff > 0 正向运动,diff < 0 反向运动
564+
const transdir = diff < 0 ? -1 : 1
565+
// 内联 getTargetPosition 的简化版
566+
const rawIndex = Math.abs(newOffset) / step.value
567+
const moveToIndex = transdir < 0 ? Math.ceil(rawIndex) : Math.floor(rawIndex)
568+
let nextIndex: number
569+
if (circularShared.value) {
570+
// 与 getTargetPosition 的边界分支对齐
571+
if (moveToIndex >= childrenLength.value + patchElmNumShared.value) {
572+
// 超过末尾 clone → 绕回头部
573+
nextIndex = moveToIndex - (childrenLength.value + patchElmNumShared.value)
574+
} else if (moveToIndex <= patchElmNumShared.value - 1) {
575+
// 超过头部 clone → 绕回尾部
576+
nextIndex = moveToIndex === 0 ? childrenLength.value - patchElmNumShared.value : childrenLength.value - 1
577+
} else {
578+
nextIndex = moveToIndex - patchElmNumShared.value
579+
}
580+
} else {
581+
// 非循环:正常 clamp
582+
nextIndex = Math.max(0, Math.min(moveToIndex, childrenLength.value - 1))
583+
}
584+
if (nextIndex !== currentIndex.value) {
585+
currentIndex.value = nextIndex
586+
}
587+
}
588+
}
589+
)
516590
// 1. 用户在当前页切换选中项,动画;用户携带选中index打开到swiper页直接选中不走动画
517591
useAnimatedReaction(() => currentIndex.value, (newIndex: number, preIndex: number) => {
518592
// 这里必须传递函数名, 直接写()=> {}形式会报 访问了未sharedValue信息
@@ -522,6 +596,25 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
522596
isFirstRef.current = false
523597
})
524598

599+
useAnimatedReaction(() => offset.value, (curOffset, preOffset) => {
600+
if (!bindtransition) return
601+
// 修正 isEqual:circular 需减去 preMargin
602+
const computeOffset = step.value * (currentIndex.value + patchElmNumShared.value)
603+
- (circularShared.value ? preMarginShared.value : 0)
604+
const isEqual = Math.abs(Math.floor(computeOffset) - Math.floor(Math.abs(curOffset))) <= 2
605+
if (curOffset !== (preOffset ?? 0) && !isEqual) {
606+
// trans = 起点坐标 - 当前坐标
607+
// x方向向前(向左)滑动:offset 变负 → trans > 0
608+
const trans = transitionSourceOffset.value - curOffset
609+
const transData = {
610+
dx: dir === 'x' ? trans : 0,
611+
dy: dir === 'y' ? trans : 0
612+
}
613+
console.log('-------------------------useAnimatedReaction3', transitionSourceOffset.value, curOffset, trans)
614+
runOnJS(runOnJSCallback)('handleTransition', transData)
615+
}
616+
})
617+
525618
useEffect(() => {
526619
let patchStep = 0
527620
if (preMargin !== preMarginShared.value) {
@@ -649,6 +742,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
649742
currentIndex.value = selectedIndex
650743
offset.value = resetOffset
651744
runOnJS(runOnJSCallback)('resumeLoop')
745+
bindanimationfinish && runOnJS(runOnJSCallback)('handleAnimationfinish', selectedIndex)
652746
}
653747
})
654748
} else {
@@ -659,6 +753,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
659753
if (touchfinish.value !== false) {
660754
currentIndex.value = selectedIndex
661755
runOnJS(runOnJSCallback)('resumeLoop')
756+
bindanimationfinish && runOnJS(runOnJSCallback)('handleAnimationfinish', selectedIndex)
662757
}
663758
})
664759
}
@@ -681,6 +776,7 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
681776
if (touchfinish.value !== false) {
682777
currentIndex.value = moveToIndex
683778
runOnJS(runOnJSCallback)('resumeLoop')
779+
bindanimationfinish && runOnJS(runOnJSCallback)('handleAnimationfinish', moveToIndex)
684780
}
685781
})
686782
}
@@ -769,9 +865,11 @@ const SwiperWrapper = forwardRef<HandlerRef<View, SwiperProps>, SwiperProps>((pr
769865
if (!step.value) return
770866
touchfinish.value = false
771867
cancelAnimation(offset)
868+
transitionSourceOffset.value = offset.value
772869
runOnJS(runOnJSCallback)('pauseLoop')
773870
preAbsolutePos.value = e[strAbso]
774871
moveTranstion.value = e[strAbso]
872+
console.log('-------------------------onBegin3', transitionSourceOffset.value)
775873
})
776874
.onUpdate((e: GestureStateChangeEvent<PanGestureHandlerEventPayload>) => {
777875
'worklet'

0 commit comments

Comments
 (0)