fixed dogshit scroll
This commit is contained in:
@@ -1,117 +1,45 @@
|
|||||||
<script setup>
|
|
||||||
import { ref, onMounted, onBeforeUnmount, watchEffect } from "vue";
|
|
||||||
|
|
||||||
const container = ref(null);
|
|
||||||
const direction = ref(1); // 1 = down, -1 = up
|
|
||||||
const isPaused = ref(false);
|
|
||||||
const animationFrameId = ref(null);
|
|
||||||
const lastTime = ref(0);
|
|
||||||
|
|
||||||
const SPEED = 0.03; // px per ms (better for frame rate independence)
|
|
||||||
const PAUSE_DURATION = 2000; // ms at top/bottom
|
|
||||||
|
|
||||||
// Use requestAnimationFrame for smoother scrolling
|
|
||||||
function scrollStep(timestamp) {
|
|
||||||
if (isPaused.value) return;
|
|
||||||
|
|
||||||
if (!lastTime.value) lastTime.value = timestamp;
|
|
||||||
const deltaTime = timestamp - lastTime.value;
|
|
||||||
lastTime.value = timestamp;
|
|
||||||
|
|
||||||
if (!container.value) return;
|
|
||||||
|
|
||||||
const el = container.value;
|
|
||||||
const scrollDistance = SPEED * deltaTime * direction.value;
|
|
||||||
|
|
||||||
el.scrollTop += scrollDistance;
|
|
||||||
|
|
||||||
const reachedBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 1;
|
|
||||||
const reachedTop = el.scrollTop <= 1;
|
|
||||||
|
|
||||||
if (reachedBottom || reachedTop) {
|
|
||||||
direction.value *= -1;
|
|
||||||
isPaused.value = true;
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
isPaused.value = false;
|
|
||||||
if (!isPaused.value) {
|
|
||||||
animationFrameId.value = requestAnimationFrame(scrollStep);
|
|
||||||
}
|
|
||||||
}, PAUSE_DURATION);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
animationFrameId.value = requestAnimationFrame(scrollStep);
|
|
||||||
}
|
|
||||||
|
|
||||||
function pauseScroll() {
|
|
||||||
isPaused.value = true;
|
|
||||||
lastTime.value = 0; // Reset time tracking
|
|
||||||
}
|
|
||||||
|
|
||||||
function resumeScroll() {
|
|
||||||
if (isPaused.value) {
|
|
||||||
isPaused.value = false;
|
|
||||||
animationFrameId.value = requestAnimationFrame(scrollStep);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function startScrolling() {
|
|
||||||
if (!isPaused.value) {
|
|
||||||
animationFrameId.value = requestAnimationFrame(scrollStep);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function stopScrolling() {
|
|
||||||
if (animationFrameId.value) {
|
|
||||||
cancelAnimationFrame(animationFrameId.value);
|
|
||||||
animationFrameId.value = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onMounted(() => {
|
|
||||||
startScrolling();
|
|
||||||
});
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
stopScrolling();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Optional: Auto-pause when component is not visible
|
|
||||||
const observer = ref(null);
|
|
||||||
onMounted(() => {
|
|
||||||
if ("IntersectionObserver" in window) {
|
|
||||||
observer.value = new IntersectionObserver(
|
|
||||||
(entries) => {
|
|
||||||
isPaused.value = !entries[0].isIntersecting;
|
|
||||||
if (!isPaused.value) {
|
|
||||||
startScrolling();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{ threshold: 0.1 },
|
|
||||||
);
|
|
||||||
|
|
||||||
if (container.value) {
|
|
||||||
observer.value.observe(container.value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
onBeforeUnmount(() => {
|
|
||||||
if (observer.value) {
|
|
||||||
observer.value.disconnect();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div
|
<div ref="container" @mouseover="handleHover" class="overflow-y-auto">
|
||||||
ref="container"
|
|
||||||
@mouseover="pauseScroll"
|
|
||||||
@mouseleave="resumeScroll"
|
|
||||||
class="overflow-y-auto"
|
|
||||||
>
|
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { useTemplateRef, onMounted, onBeforeUnmount } from "vue";
|
||||||
|
|
||||||
|
const container = useTemplateRef("container");
|
||||||
|
|
||||||
|
const SPEED = 1; // px per frame
|
||||||
|
const PAUSE = 2000; // ms at top/bottom
|
||||||
|
const FRAME_TIME = 50; // ms at top/bottom
|
||||||
|
|
||||||
|
let direction = 1; // 1 = down, -1 = up
|
||||||
|
let timeoutId;
|
||||||
|
|
||||||
|
function handleHover() {
|
||||||
|
cancelAnimationFrame(timeoutId);
|
||||||
|
setTimeout(() => requestAnimationFrame(tick), PAUSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
function tick() {
|
||||||
|
const el = container.value;
|
||||||
|
el.scrollTop += SPEED * direction;
|
||||||
|
|
||||||
|
const reachedBottom = el.scrollTop + el.clientHeight >= el.scrollHeight;
|
||||||
|
const reachedTop = el.scrollTop <= 0;
|
||||||
|
|
||||||
|
if (reachedBottom || reachedTop) {
|
||||||
|
direction *= -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeoutId = requestAnimationFrame(tick);
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
timeoutId = requestAnimationFrame(tick);
|
||||||
|
});
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
cancelAnimationFrame(timeoutId);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user