PullDownToRefresh: fix trigger many refreshings

This commit fixes that the wheel event path may
trigger too many refreshings.
This commit is contained in:
thislight 2024-10-09 14:51:32 +08:00
parent 40a785a538
commit ee39cf8651
No known key found for this signature in database
GPG key ID: A50F9451AC56A63E

View file

@ -28,11 +28,13 @@ const PullDownToRefresh: Component<{
let rootElement: HTMLDivElement; let rootElement: HTMLDivElement;
const [pullDown, setPullDown] = createSignal(0); const [pullDown, setPullDown] = createSignal(0);
const pullDownDistance = () => { const stopPos = () => 160
const indicatorOfsY = () => {
if (props.loading) { if (props.loading) {
return 140; return stopPos() * 0.875;
} }
return Math.max(Math.min(160, pullDown()), 0); return pullDown();
}; };
const obvx = createVisibilityObserver({ const obvx = createVisibilityObserver({
@ -55,7 +57,7 @@ const PullDownToRefresh: Component<{
const vspring = holding ? 0 : K * x * dt; const vspring = holding ? 0 : K * x * dt;
v = ds / dt - vspring; v = ds / dt - vspring;
setPullDown(x + v * dt); setPullDown(Math.max(Math.min(x + v * dt, stopPos()), 0));
if (Math.abs(x) > 1 || Math.abs(v) > 1) { if (Math.abs(x) > 1 || Math.abs(v) > 1) {
requestAnimationFrame(updatePullDown); requestAnimationFrame(updatePullDown);
@ -66,12 +68,11 @@ const PullDownToRefresh: Component<{
if ( if (
!holding && !holding &&
untrack(pullDownDistance) >= 160 && untrack(pullDown) >= stopPos() &&
!props.loading && !props.loading &&
props.onRefresh props.onRefresh
) { ) {
setTimeout(props.onRefresh, 0); setTimeout(props.onRefresh, 0);
// FIXME: this may trigger at multiple frames
} }
} finally { } finally {
ds = 0; ds = 0;
@ -91,11 +92,12 @@ const PullDownToRefresh: Component<{
if (scrollTop >= 0 && scrollTop < 1) { if (scrollTop >= 0 && scrollTop < 1) {
event.preventDefault() event.preventDefault()
ds = -(event.deltaY / window.devicePixelRatio / 2); ds = -(event.deltaY / window.devicePixelRatio / 2);
holding = true; holding = untrack(pullDown) < stopPos();
if (wheelTimeout) { if (wheelTimeout) {
clearTimeout(wheelTimeout); clearTimeout(wheelTimeout);
} }
wheelTimeout = setTimeout(onWheelNotUpdated, 200); wheelTimeout = setTimeout(onWheelNotUpdated, 200);
if (released) { if (released) {
released = false; released = false;
requestAnimationFrame(updatePullDown); requestAnimationFrame(updatePullDown);
@ -130,7 +132,7 @@ const PullDownToRefresh: Component<{
} }
holding = true; holding = true;
if (lastTouchScreenY !== 0) { if (lastTouchScreenY !== 0) {
ds = (item.screenY - lastTouchScreenY) / window.devicePixelRatio; ds = (item.screenY - lastTouchScreenY) ;
} }
lastTouchScreenY = item.screenY; lastTouchScreenY = item.screenY;
if (released) { if (released) {
@ -143,7 +145,7 @@ const PullDownToRefresh: Component<{
lastTouchId = undefined; lastTouchId = undefined;
lastTouchScreenY = 0; lastTouchScreenY = 0;
holding = false; holding = false;
if (untrack(pullDownDistance) >= 160 && !props.loading && props.onRefresh) { if (untrack(indicatorOfsY) >= 160 && !props.loading && props.onRefresh) {
setTimeout(props.onRefresh, 0); setTimeout(props.onRefresh, 0);
} else { } else {
if (released) { if (released) {
@ -185,14 +187,14 @@ const PullDownToRefresh: Component<{
aspect-ratio: 1/1; aspect-ratio: 1/1;
width: 2rem; width: 2rem;
color: var(--tutu-color-primary); color: var(--tutu-color-primary);
transform: translateY(${`${pullDownDistance() - 2}px`}); transform: translateY(${`${indicatorOfsY() - 2}px`});
will-change: transform; will-change: transform;
z-index: var(--tutu-zidx-nav); z-index: var(--tutu-zidx-nav);
background-color: var(--tutu-color-surface); background-color: var(--tutu-color-surface);
> :global(.refresh-icon) { > :global(.refresh-icon) {
transform: rotate( transform: rotate(
${`${((pullDownDistance() / 160) * 180).toString()}deg`} ${`${((indicatorOfsY() / 160) * 180).toString()}deg`}
); );
will-change: transform; will-change: transform;
} }