From e0ae206c8923e1c0312ce50bc3cdf96ce3a81c2b Mon Sep 17 00:00:00 2001 From: inottn Date: Fri, 5 May 2023 21:38:52 +0800 Subject: [PATCH] fix(Tab): should cancel raf before the next scroll (#11819) * fix(Tab): should cancel raf before the next scroll * fix(Tab): consider the case where multiple components exist at the same time --- packages/vant/src/tabs/Tabs.tsx | 13 +++++++++++-- packages/vant/src/tabs/utils.ts | 23 ++++++++++++++++++----- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/packages/vant/src/tabs/Tabs.tsx b/packages/vant/src/tabs/Tabs.tsx index 0acc49eeb..6bbcfdb4c 100644 --- a/packages/vant/src/tabs/Tabs.tsx +++ b/packages/vant/src/tabs/Tabs.tsx @@ -97,6 +97,8 @@ export default defineComponent({ let tabHeight: number; let lockScroll: boolean; let stickyFixed: boolean; + let cancelScrollLeftToRaf: (() => void) | undefined; + let cancelScrollTopToRaf: (() => void) | undefined; const root = ref(); const navRef = ref(); @@ -160,7 +162,12 @@ export default defineComponent({ const title = titles[state.currentIndex].$el; const to = title.offsetLeft - (nav.offsetWidth - title.offsetWidth) / 2; - scrollLeftTo(nav, to, immediate ? 0 : +props.duration); + if (cancelScrollLeftToRaf) cancelScrollLeftToRaf(); + cancelScrollLeftToRaf = scrollLeftTo( + nav, + to, + immediate ? 0 : +props.duration + ); }; // update nav bar style @@ -275,7 +282,9 @@ export default defineComponent({ const to = getElementTop(target, scroller.value) - scrollOffset.value; lockScroll = true; - scrollTopTo( + + if (cancelScrollTopToRaf) cancelScrollTopToRaf(); + cancelScrollTopToRaf = scrollTopTo( scroller.value, to, immediate ? 0 : +props.duration, diff --git a/packages/vant/src/tabs/utils.ts b/packages/vant/src/tabs/utils.ts index a1d7fea53..d969c70b4 100644 --- a/packages/vant/src/tabs/utils.ts +++ b/packages/vant/src/tabs/utils.ts @@ -1,4 +1,4 @@ -import { raf } from '@vant/use'; +import { raf, cancelRaf } from '@vant/use'; import { ScrollElement, getScrollTop, setScrollTop } from '../utils'; export function scrollLeftTo( @@ -6,19 +6,26 @@ export function scrollLeftTo( to: number, duration: number ) { + let rafId: number; let count = 0; const from = scroller.scrollLeft; const frames = duration === 0 ? 1 : Math.round((duration * 1000) / 16); + function cancel() { + cancelRaf(rafId); + } + function animate() { scroller.scrollLeft += (to - from) / frames; if (++count < frames) { - raf(animate); + rafId = raf(animate); } } animate(); + + return cancel; } export function scrollTopTo( @@ -27,12 +34,16 @@ export function scrollTopTo( duration: number, callback: () => void ) { + let rafId: number; let current = getScrollTop(scroller); - const isDown = current < to; const frames = duration === 0 ? 1 : Math.round((duration * 1000) / 16); const step = (to - current) / frames; + function cancel() { + cancelRaf(rafId); + } + function animate() { current += step; @@ -43,11 +54,13 @@ export function scrollTopTo( setScrollTop(scroller, current); if ((isDown && current < to) || (!isDown && current > to)) { - raf(animate); + rafId = raf(animate); } else if (callback) { - raf(callback as FrameRequestCallback); + rafId = raf(callback as FrameRequestCallback); } } animate(); + + return cancel; }