Skip to content

Commit a938bcb

Browse files
committed
fix: requestAnimationFrame error in ssr, close #4833
1 parent 7b03f8a commit a938bcb

File tree

15 files changed

+57
-45
lines changed

15 files changed

+57
-45
lines changed

components/_util/openAnimation.js

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import cssAnimation from './css-animation';
22
import { nextTick } from 'vue';
3+
import { requestAnimationTimeout, cancelAnimationTimeout } from './requestAnimationTimeout';
34

45
function animate(node, show, done) {
56
let height;
@@ -8,7 +9,7 @@ function animate(node, show, done) {
89
return cssAnimation(node, 'ant-motion-collapse-legacy', {
910
start() {
1011
if (appearRequestAnimationFrameId) {
11-
cancelAnimationFrame(appearRequestAnimationFrameId);
12+
cancelAnimationTimeout(appearRequestAnimationFrameId);
1213
}
1314
if (!show) {
1415
node.style.height = `${node.offsetHeight}px`;
@@ -18,7 +19,7 @@ function animate(node, show, done) {
1819
// not get offsetHeight when appear
1920
// set it into raf get correct offsetHeight
2021
if (height === 0) {
21-
appearRequestAnimationFrameId = requestAnimationFrame(() => {
22+
appearRequestAnimationFrameId = requestAnimationTimeout(() => {
2223
height = node.offsetHeight;
2324
node.style.height = '0px';
2425
node.style.opacity = '0';
@@ -31,19 +32,19 @@ function animate(node, show, done) {
3132
},
3233
active() {
3334
if (requestAnimationFrameId) {
34-
cancelAnimationFrame(requestAnimationFrameId);
35+
cancelAnimationTimeout(requestAnimationFrameId);
3536
}
36-
requestAnimationFrameId = requestAnimationFrame(() => {
37+
requestAnimationFrameId = requestAnimationTimeout(() => {
3738
node.style.height = `${show ? height : 0}px`;
3839
node.style.opacity = show ? '1' : '0';
3940
});
4041
},
4142
end() {
4243
if (appearRequestAnimationFrameId) {
43-
cancelAnimationFrame(appearRequestAnimationFrameId);
44+
cancelAnimationTimeout(appearRequestAnimationFrameId);
4445
}
4546
if (requestAnimationFrameId) {
46-
cancelAnimationFrame(requestAnimationFrameId);
47+
cancelAnimationTimeout(requestAnimationFrameId);
4748
}
4849
node.style.height = '';
4950
node.style.opacity = '';

components/_util/raf.ts

+14-17
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,33 @@
1-
interface RafMap {
2-
[id: number]: number;
3-
}
1+
import getRequestAnimationFrame, { cancelRequestAnimationFrame } from './getRequestAnimationFrame';
42

5-
let id = 0;
6-
const ids: RafMap = {};
3+
const oriRaf = getRequestAnimationFrame();
74

5+
export type RafFrame = {
6+
id: number;
7+
};
88
// Support call raf with delay specified frame
9-
export default function raf(callback: () => void, delayFrames = 1): number {
10-
const myId: number = id++;
9+
export default function raf(callback: () => void, delayFrames = 1): { id: number } {
1110
let restFrames: number = delayFrames;
1211

1312
function internalCallback() {
1413
restFrames -= 1;
1514

1615
if (restFrames <= 0) {
1716
callback();
18-
delete ids[myId];
1917
} else {
20-
ids[myId] = requestAnimationFrame(internalCallback);
18+
frame.id = oriRaf(internalCallback);
2119
}
2220
}
2321

24-
ids[myId] = requestAnimationFrame(internalCallback);
22+
const frame = {
23+
id: oriRaf(internalCallback),
24+
};
2525

26-
return myId;
26+
return frame;
2727
}
2828

29-
raf.cancel = function cancel(pid?: number) {
30-
if (pid === undefined) return;
29+
raf.cancel = function cancel(frame?: { id: number }) {
30+
if (!frame) return;
3131

32-
cancelAnimationFrame(ids[pid]);
33-
delete ids[pid];
32+
cancelRequestAnimationFrame(frame.id);
3433
};
35-
36-
raf.ids = ids; // export this for test usage

components/_util/throttleByAnimationFrame.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
import type { RafFrame } from './raf';
2+
import raf from './raf';
3+
14
export default function throttleByAnimationFrame(fn: (...args: any[]) => void) {
2-
let requestId: number | null;
5+
let requestId: RafFrame;
36

47
const later = (args: any[]) => () => {
58
requestId = null;
@@ -8,11 +11,11 @@ export default function throttleByAnimationFrame(fn: (...args: any[]) => void) {
811

912
const throttled = (...args: any[]) => {
1013
if (requestId == null) {
11-
requestId = requestAnimationFrame(later(args));
14+
requestId = raf(later(args));
1215
}
1316
};
1417

15-
(throttled as any).cancel = () => cancelAnimationFrame(requestId!);
18+
(throttled as any).cancel = () => raf.cancel(requestId!);
1619

1720
return throttled;
1821
}

components/menu/src/PopupTrigger.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { computed, defineComponent, onBeforeUnmount, ref, watch } from 'vue';
44
import type { MenuMode } from './interface';
55
import { useInjectMenu } from './hooks/useMenuContext';
66
import { placements, placementsRtl } from './placements';
7+
import type { RafFrame } from '../../_util/raf';
78
import raf from '../../_util/raf';
89
import classNames from '../../_util/classNames';
910

@@ -48,7 +49,7 @@ export default defineComponent({
4849

4950
const popupPlacement = computed(() => popupPlacementMap[props.mode]);
5051

51-
const visibleRef = ref<number>();
52+
const visibleRef = ref<RafFrame>();
5253
watch(
5354
() => props.visible,
5455
visible => {

components/slider/SliderTooltip.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { onBeforeUnmount, watch, onActivated, defineComponent, ref } from 'vue';
22
import Tooltip, { tooltipProps } from '../tooltip';
3+
import type { RafFrame } from '../_util/raf';
34
import raf from '../_util/raf';
45

56
export default defineComponent({
@@ -9,7 +10,7 @@ export default defineComponent({
910
setup(props, { attrs, slots }) {
1011
const innerRef = ref<any>(null);
1112

12-
const rafRef = ref<number | null>(null);
13+
const rafRef = ref<RafFrame>(null);
1314

1415
function cancelKeepAlign() {
1516
raf.cancel(rafRef.value!);

components/vc-image/src/hooks/useFrameSetState.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1+
import type { RafFrame } from '../../../_util/raf';
12
import raf from '../../../_util/raf';
23
import { onMounted, reactive, ref } from 'vue';
34

45
type SetActionType<T> = Partial<T> | ((state: T) => Partial<T>);
56
export default function useFrameSetState<T extends object>(
67
initial: T,
78
): [Record<string, any>, (newState: SetActionType<T>) => void] {
8-
const frame = ref(null);
9+
const frame = ref<RafFrame>(null);
910
const state = reactive({ ...initial });
1011
const queue = ref<SetActionType<T>[]>([]);
1112

components/vc-picker/hooks/useHoverValue.ts

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import type { RafFrame } from '../../_util/raf';
2+
import raf from '../../_util/raf';
13
import type { ComputedRef, Ref, UnwrapRef } from 'vue';
24
import { ref, onBeforeUnmount, watch } from 'vue';
35
import type { ValueTextConfig } from './useValueTexts';
@@ -8,15 +10,15 @@ export default function useHoverValue<DateType>(
810
{ formatList, generateConfig, locale }: ValueTextConfig<DateType>,
911
): [ComputedRef<string>, (date: DateType) => void, (immediately?: boolean) => void] {
1012
const innerValue = ref<DateType>(null);
11-
const raf = ref(null);
13+
let rafId: RafFrame;
1214

1315
function setValue(val: DateType, immediately = false) {
14-
cancelAnimationFrame(raf.value);
16+
raf.cancel(rafId);
1517
if (immediately) {
1618
innerValue.value = val as UnwrapRef<DateType>;
1719
return;
1820
}
19-
raf.value = requestAnimationFrame(() => {
21+
rafId = raf(() => {
2022
innerValue.value = val as UnwrapRef<DateType>;
2123
});
2224
}
@@ -38,7 +40,7 @@ export default function useHoverValue<DateType>(
3840
onLeave(true);
3941
});
4042
onBeforeUnmount(() => {
41-
cancelAnimationFrame(raf.value);
43+
raf.cancel(rafId);
4244
});
4345

4446
return [firstText, onEnter, onLeave];

components/vc-picker/hooks/usePickerInput.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { onBeforeUnmount, watchEffect, watch, ref, computed } from 'vue';
33
import type { FocusEventHandler } from '../../_util/EventInterface';
44
import KeyCode from '../../_util/KeyCode';
55
import { addGlobalMousedownEvent, getTargetFromEvent } from '../utils/uiUtil';
6+
import raf from '../../_util/raf';
67

78
export default function usePickerInput({
89
open,
@@ -161,7 +162,7 @@ export default function usePickerInput({
161162
preventBlurRef.value = true;
162163

163164
// Always set back in case `onBlur` prevented by user
164-
requestAnimationFrame(() => {
165+
raf(() => {
165166
preventBlurRef.value = false;
166167
});
167168
} else if (!focused.value || clickedOutside) {

components/vc-picker/utils/uiUtil.ts

+6-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
import isVisible from '../../vc-util/Dom/isVisible';
22
import KeyCode from '../../_util/KeyCode';
3+
import type { RafFrame } from '../../_util/raf';
34
import raf from '../../_util/raf';
45
import type { GenerateConfig } from '../generate';
56
import type { CustomFormat, PanelMode, PickerMode } from '../interface';
67

7-
const scrollIds = new Map<HTMLElement, number>();
8+
const scrollIds = new Map<HTMLElement, RafFrame>();
89

910
/** Trigger when element is visible in view */
1011
export function waitElementReady(element: HTMLElement, callback: () => void): () => void {
11-
let id: number;
12+
let id: RafFrame;
1213

1314
function tryOrNextFrame() {
1415
if (isVisible(element)) {
@@ -30,14 +31,14 @@ export function waitElementReady(element: HTMLElement, callback: () => void): ()
3031
/* eslint-disable no-param-reassign */
3132
export function scrollTo(element: HTMLElement, to: number, duration: number) {
3233
if (scrollIds.get(element)) {
33-
cancelAnimationFrame(scrollIds.get(element)!);
34+
raf.cancel(scrollIds.get(element)!);
3435
}
3536

3637
// jump to target if duration zero
3738
if (duration <= 0) {
3839
scrollIds.set(
3940
element,
40-
requestAnimationFrame(() => {
41+
raf(() => {
4142
element.scrollTop = to;
4243
}),
4344
);
@@ -49,7 +50,7 @@ export function scrollTo(element: HTMLElement, to: number, duration: number) {
4950

5051
scrollIds.set(
5152
element,
52-
requestAnimationFrame(() => {
53+
raf(() => {
5354
element.scrollTop += perTick;
5455
if (element.scrollTop !== to) {
5556
scrollTo(element, to, duration - 10);

components/vc-table/Header/DragHandle.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import addEventListenerWrap from '../../vc-util/Dom/addEventListener';
22
import type { EventHandler } from '../../_util/EventInterface';
3+
import type { RafFrame } from '../../_util/raf';
34
import raf from '../../_util/raf';
45
import { defineComponent, onUnmounted, computed, ref, watchEffect, getCurrentInstance } from 'vue';
56
import type { PropType } from 'vue';
@@ -73,7 +74,7 @@ export default defineComponent({
7374
const instance = getCurrentInstance();
7475
let baseWidth = 0;
7576
const dragging = ref(false);
76-
let rafId: number;
77+
let rafId: RafFrame;
7778
const updateWidth = (e: HandleEvent) => {
7879
let pageX = 0;
7980
if (e.touches) {

components/vc-table/hooks/useFrame.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import type { RafFrame } from '../../_util/raf';
12
import raf from '../../_util/raf';
23
import type { Ref, UnwrapRef } from 'vue';
34
import { onBeforeUnmount, ref, shallowRef } from 'vue';
@@ -8,7 +9,7 @@ export function useLayoutState<State>(
89
defaultState: State,
910
): [Ref<State>, (updater: Updater<State>) => void] {
1011
const stateRef = shallowRef<State>(defaultState);
11-
let rafId: number;
12+
let rafId: RafFrame;
1213
const updateBatchRef = shallowRef<Updater<State>[]>([]);
1314
function setFrameState(updater: Updater<State>) {
1415
updateBatchRef.value.push(updater);

components/vc-trigger/Popup/useVisibleStatus.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { Ref } from 'vue';
22
import { nextTick, onBeforeUnmount, ref, watch, onMounted } from 'vue';
3+
import type { RafFrame } from '../../_util/raf';
34
import raf from '../../_util/raf';
45

56
/**
@@ -23,7 +24,7 @@ export default (
2324
doMeasure: Func,
2425
): [Ref<PopupStatus>, (callback?: () => void) => void] => {
2526
const status = ref<PopupStatus>(null);
26-
const rafRef = ref<number>();
27+
const rafRef = ref<RafFrame>();
2728
const destroyRef = ref(false);
2829
function setStatus(nextStatus: PopupStatus) {
2930
if (!destroyRef.value) {

components/vc-virtual-list/hooks/useFrameWheel.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import type { Ref } from 'vue';
2+
import type { RafFrame } from '../../_util/raf';
23
import raf from '../../_util/raf';
34
import isFF from '../utils/isFirefox';
45
import useOriginScroll from './useOriginScroll';
@@ -15,7 +16,7 @@ export default function useFrameWheel(
1516
onWheelDelta: (offset: number) => void,
1617
): [(e: WheelEvent) => void, (e: FireFoxDOMMouseScrollEvent) => void] {
1718
let offsetRef = 0;
18-
let nextFrame: number | null | undefined = null;
19+
let nextFrame: RafFrame = null;
1920

2021
// Firefox patch
2122
let wheelValue = null;

components/vc-virtual-list/hooks/useScrollTo.tsx

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { Data } from '../../_util/type';
22
import type { ComputedRef, Ref } from 'vue';
3+
import type { RafFrame } from '../../_util/raf';
34
import raf from '../../_util/raf';
45
import type { GetKey } from '../interface';
56

@@ -13,7 +14,7 @@ export default function useScrollTo(
1314
syncScrollTop: (newTop: number) => void,
1415
triggerFlash: () => void,
1516
) {
16-
let scroll: number | null = null;
17+
let scroll: RafFrame = null;
1718

1819
return (arg?: any) => {
1920
// When not argument provided, we think dev may want to show the scrollbar

package.json

-1
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,6 @@
102102
"@types/markdown-it": "^10.0.2",
103103
"@types/node": "^14.0.0",
104104
"@types/postcss-load-config": "^2.0.1",
105-
"@types/raf": "^3.4.0",
106105
"@typescript-eslint/eslint-plugin": "^4.1.0",
107106
"@typescript-eslint/parser": "^4.1.0",
108107
"@vitejs/plugin-vue": "^1.2.4",

0 commit comments

Comments
 (0)