目前正在开发 Nuxt 3 应用程序,该应用程序包含目前仅适用于水平滚动的轮播功能。但是,我遇到了一个问题,即只有拥有触控板的用户才能滚动。
为了解决这个问题,我想出了实现“抓取和滚动”事件的想法,允许用户通过单击并向左或向右拖动来滚动轮播。
我尝试了多种解决方案,但我目前的代码如下:
const carousel: any = ref();
const items: any = reactive([]);
const images: any = reactive([]);
const progressLine: any = ref();
const progress: any = ref(0);
const progressContent: any = ref(0);
const tweened = reactive({
number: 0,
});
const duration = reactive({ number: 1 });
onMounted(async () => {
await nextTick();
let carouselWidth: any = carousel.value.clientWidth;
let itemWidth: any = items[0].clientWidth;
let itemPadding: any = 16 * (items.length - 1);
let wrapWidth: any = items.length * itemWidth + itemPadding;
let scrollPosition = 0;
let maxScrollPosition: any;
// Calculate the maximum scroll position
maxScrollPosition = wrapWidth - carouselWidth;
let handleScrollEvent = (e: { deltaX: any }) => {
const { deltaX } = e;
// Update the scroll position based on the mousewheel delta
scrollPosition += deltaX;
// Clamp the scroll position to prevent scrolling beyond the carousel edges
scrollPosition = Math.max(0, Math.min(scrollPosition, maxScrollPosition));
// Calculate the progress of the scroll position as a percentage
progress.value = (scrollPosition / maxScrollPosition) * 100;
progressContent.value = progress.value;
// Use GSAP to animate the carousel to the new scroll position
gsap.to(carousel.value, { duration: duration.number, ease: 'expo.out', x: -scrollPosition });
// Update the progress line width to match the scroll position
gsap.to(progressLine.value, { duration: duration.number, ease: 'expo.out', width: `${progress.value}%` });
};
let handleTouchEvent = (e: {
deltaX: any,
touches: {
clientX: any,
0: { clientX: any },
}[],
}) => {
const { touches } = e;
// Get the touch position
const touchPosition = touches[0].clientX;
// Update the scroll position based on the touch delta
scrollPosition += touchPosition;
// Clamp the scroll position to prevent scrolling beyond the carousel edges
scrollPosition = Math.max(0, Math.min(scrollPosition, maxScrollPosition));
// Calculate the progress of the scroll position as a percentage
progress.value = (scrollPosition / maxScrollPosition) * 100;
progressContent.value = progress.value;
// Use GSAP to animate the carousel to the new scroll position
gsap.to(carousel.value, { duration: duration.number, ease: 'expo.out', x: -scrollPosition });
// Update the progress line width to match the scroll position
gsap.to(progressLine.value, { duration: duration.number, ease: 'expo.out', width: `${progress.value}%` });
};
carousel.value.addEventListener('wheel', handleScrollEvent);
carousel.value.addEventListener('touchmove', handleTouchEvent);
window.addEventListener('resize', () => {
carouselWidth = carousel.value.clientWidth;
itemWidth = items[0].clientWidth;
itemPadding = 16 * items.length;
wrapWidth = items.length * itemWidth + itemPadding;
});
});
<ul class="slider" ref="carousel">
<li v-for="(project, i) in fetchedProjects" :key="project.slug" class="project-item" ref="items">
<NuxtLink ref="project" v-if="project.img" class="project-link">
<div class="project-figure">
<img
:src="'https://picsum.photos/5' + i.toString().padStart(2, '0')"
:alt="project.description"
class="project-figure_img"
ref="images"
/>
<span class="project-figure_span">{{ project.name }}</span>
</div>
</NuxtLink>
</li>
</ul>
ul.slider {
--imgSize: 14.6875rem;
height: 100%;
display: inline-flex;
flex-wrap: nowrap;
li.project-item {
flex: 0 0 var(--imgSize);
&:not(:last-of-type) {
margin-right: 1em;
}
div.project-figure {
user-select: none;
img {
pointer-events: none;
user-select: none;
height: var(--imgSize);
width: var(--imgSize);
object-fit: cover;
}
span {
display: none;
}
}
}
}
但是,它没有按预期工作。每次我尝试滚动旋转木马时,它都会重置到起始位置,就好像滚动是相对于窗口大小而不是旋转木马本身一样。这种行为很奇怪。
虽然“水平滚动”事件有效。