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
This commit is contained in:
inottn 2023-05-05 21:38:52 +08:00 committed by GitHub
parent bfd9995583
commit e0ae206c89
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 29 additions and 7 deletions

View File

@ -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<HTMLElement>();
const navRef = ref<HTMLElement>();
@ -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,

View File

@ -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;
}