|
|
|
import type { Ref } from 'vue';
|
|
|
|
import raf from '../../_util/raf';
|
|
|
|
import isFF from '../utils/isFirefox';
|
|
|
|
import useOriginScroll from './useOriginScroll';
|
|
|
|
|
|
|
|
interface FireFoxDOMMouseScrollEvent {
|
|
|
|
detail: number;
|
|
|
|
preventDefault: Function;
|
|
|
|
}
|
|
|
|
|
|
|
|
export default function useFrameWheel(
|
|
|
|
inVirtual: Ref<boolean>,
|
|
|
|
isScrollAtTop: Ref<boolean>,
|
|
|
|
isScrollAtBottom: Ref<boolean>,
|
|
|
|
onWheelDelta: (offset: number) => void,
|
|
|
|
): [(e: WheelEvent) => void, (e: FireFoxDOMMouseScrollEvent) => void] {
|
|
|
|
let offsetRef = 0;
|
|
|
|
let nextFrame: number = null;
|
|
|
|
|
|
|
|
// Firefox patch
|
|
|
|
let wheelValue = null;
|
|
|
|
let isMouseScroll = false;
|
|
|
|
|
|
|
|
// Scroll status sync
|
|
|
|
const originScroll = useOriginScroll(isScrollAtTop, isScrollAtBottom);
|
|
|
|
|
|
|
|
function onWheel(event: { preventDefault?: any; deltaY?: any }) {
|
|
|
|
if (!inVirtual.value) return;
|
|
|
|
|
|
|
|
raf.cancel(nextFrame!);
|
|
|
|
|
|
|
|
const { deltaY } = event;
|
|
|
|
offsetRef += deltaY;
|
|
|
|
wheelValue = deltaY;
|
|
|
|
|
|
|
|
// Do nothing when scroll at the edge, Skip check when is in scroll
|
|
|
|
if (originScroll(deltaY)) return;
|
|
|
|
|
|
|
|
// Proxy of scroll events
|
|
|
|
if (!isFF) {
|
|
|
|
event.preventDefault();
|
|
|
|
}
|
|
|
|
|
|
|
|
nextFrame = raf(() => {
|
|
|
|
// Patch a multiple for Firefox to fix wheel number too small
|
|
|
|
// ref: https://github.com/ant-design/ant-design/issues/26372#issuecomment-679460266
|
|
|
|
const patchMultiple = isMouseScroll ? 10 : 1;
|
|
|
|
onWheelDelta(offsetRef * patchMultiple);
|
|
|
|
offsetRef = 0;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
// A patch for firefox
|
|
|
|
function onFireFoxScroll(event: { detail: any }) {
|
|
|
|
if (!inVirtual.value) return;
|
|
|
|
|
|
|
|
isMouseScroll = event.detail === wheelValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
return [onWheel, onFireFoxScroll];
|
|
|
|
}
|