我有一个垂直滑块,我使用滑动器来浏览幻灯片。
每个 swiper-slide 容器高度为 100vh。
我有一张幻灯片,其内容大于视图高度,当使用鼠标滚轮滚动时,我想首先滚动其内容,当到达末尾或顶部时,根据滚动方向移动到下一张或上一张幻灯片。
我浏览了 swiper 文档、SO 和其他页面,但没有找到解决方案。
这是jsfiddle: https://jsfiddle.net/gentian28/6wdsep1v/13/
HTML
<div class="swiper-container">
<main class="main swiper-wrapper">
<!-- landing -->
<section id="home" class="swiper-slide">
<div id="particles-js"></div>
<div id="typeIt" class="d-flex align-center"></div>
</section>
<!-- about -->
<section id="about" class="swiper-slide">
<span class="animation">About</span>
</section>
<!-- portfolio -->
<section id="portfolio" class="swiper-slide d-flex flex-wrap col-3">
<div class="card">
card 1
</div>
<div class="card">
card 2
</div>
<div class="card">
card 3
</div>
<div class="card">
card 4
</div>
<div class="card">
card 1
</div>
<div class="card">
card 1
</div>
<div class="card">
card 1
</div>
<div class="card">
card 1
</div>
<div class="card">
card 1
</div>
<div class="card">
card 1
</div>
<div class="card">
card 1
</div>
</section>
<!-- technologies -->
<section id="skills" class="swiper-slide">
Skills
</section>
<!-- contact -->
<section id="contact" class="swiper-slide">
Contact
</section>
</main>
</div>
CSS
body {
margin: 0;
padding: 0;
}
.d-flex {
display: flex;
}
.align-center {
align-items: center;
}
.justify-center {
justify-content: center;
}
.justify-between {
justify-content: space-between;
}
.flex-column {
flex-flow: column;
}
.column-reverse {
flex-flow: column-reverse;
}
.flex-wrap {
flex-wrap: wrap;
}
.col-2 > * {
width: calc(100% / 2 - 7.5px);
margin-right: 15px;
margin-bottom: 15px;
}
.col-2 > *:nth-child(2n) {
margin-right: 0;
}
.col-3 > * {
width: calc(100% / 3 - 10px);
margin-right: 15px;
}
.col-3 > *:nth-child(3n) {
margin-right: 0;
}
.col-4 > * {
width: calc(100% / 4 - 10.5px);
margin-right: 14px;
}
.col-4 > *:nth-child(4n) {
margin-right: 0;
}
.card {
height: 300px;
}
.swiper-container {
width: 100% - 120px;
height: 100vh;
margin-left: auto;
margin-right: auto;
}
.swiper-slide {
text-align: center;
font-size: 18px;
background: #fff;
/* Center slide text vertically */
display: -webkit-box;
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
-webkit-box-pack: center;
-ms-flex-pack: center;
-webkit-justify-content: center;
justify-content: center;
-webkit-box-align: center;
-ms-flex-align: center;
-webkit-align-items: center;
align-items: center;
overflow-y: auto;
}
.swiper-pagination {
display: flex;
flex-flow: column;
}
.swiper-pagination-bullet-active {
opacity: 0;
}
.swiper-pagination-bullet {
width: 120px;
height: 96px;
border-radius: 0;
opacity: 0;
}
JS
const swiperConf = {
direction: 'vertical',
slidesPerView: 1,
spaceBetween: -1,
mousewheel: true,
keyboard: true,
pagination: {
el: '.swiper-pagination',
clickable: true,
}
}
var swiper = new Swiper('.swiper-container', swiperConf);
啊伙计们!非常感谢您的意见,我也遇到了同样的问题。但您的解决方案在移动设备上不适用于我。 所以我根据你的输入尝试了一些东西,并进行了一些修改。 所以这是我的: (我在堆栈溢出上的第一篇文章)
const handleScrollInside = (swiper) => {
swiper.on("slideChangeTransitionEnd", () => {
const activeSlide = document.querySelector('.swiper-slide-active');
const hasVerticalScrollbar = activeSlide.scrollHeight > activeSlide.clientHeight;
if (hasVerticalScrollbar) {
const scrollDifferenceTop = activeSlide.scrollHeight - activeSlide.swiperSlideSize;
if (activeSlide.scrollTop === 0) activeSlide.scrollTop += 1;
if (activeSlide.scrollTop === scrollDifferenceTop) activeSlide.scrollTop -= 2;
swiper.mousewheel.disable();
swiper.allowTouchMove = false;
activeSlide.addEventListener("scroll", () => {
if (activeSlide.scrollTop <= 0 || scrollDifferenceTop - activeSlide.scrollTop <= 1 ) {
swiper.mousewheel.enable();
swiper.allowTouchMove = true;
}
});
}
})
}
也遇到了这个问题,@Daryll 的小提琴非常有帮助,但是使用 typescript 从 HTMLElement 获取“swiperSlideSize”时存在一些问题(也使用reactjs存在一些差异)。这对我来说是“onSlideChangeTransitionEnd”的事件处理程序:
const allowScroll = (swiper: SwiperEvent) => {
var activeIndex = swiper.activeIndex;
var activeSlide = swiper.slides[activeIndex];
var { scrollHeight, clientHeight } = activeSlide;
const diff = scrollHeight - clientHeight;
if (diff > 0) {
const findScroll = (e) => {
const scrollUp = e.deltaY < 0;
if (scrollUp && activeSlide.scrollTop === 0) {
swiper.mousewheel.enable();
activeSlide.removeEventListener("wheel", findScroll);
} else if (!scrollUp && activeSlide.scrollTop === diff) {
swiper.mousewheel.enable();
activeSlide.scrollTop = 0;
activeSlide.removeEventListener("wheel", findScroll);
}
};
activeSlide.addEventListener("wheel", findScroll);
swiper.mousewheel.disable();
}
};
编辑:“SwiperEvent”类型是我与
import { Swiper as SwiperEvent } from "swiper";
一起使用的别名,以避免与 import { Swiper } from "swiper/react";
发生命名空间冲突
编辑2:对于移动使用,您必须考虑“touchmove”事件,它不会(总是?)注册“wheel”事件。通过禁用滑动器上的“allowTouchMove”,您可以在移动设备上实现与在桌面上使用
mousewheel.disable()
相同的效果。这是该案例的一些代码:
const allowScroll = (swiper: SwiperEvent) => {
var activeIndex = swiper.activeIndex;
var activeSlide = swiper.slides[activeIndex];
var { scrollHeight, clientHeight } = activeSlide;
const diff = scrollHeight - clientHeight;
if (activeSlide.scrollTop === 0) activeSlide.scrollTop = 1;
else if (activeSlide.scrollTop === diff) activeSlide.scrollTop = diff - 1;
if (diff > 0) {
const findScroll = (e) => {
const scrollUp = e.deltaY < 0;
if (
(scrollUp || e.type === "touchmove") &&
activeSlide.scrollTop <= 0
) {
swiper.mousewheel.enable();
swiper.allowTouchMove = true;
activeSlide.removeEventListener("wheel", findScroll);
activeSlide.removeEventListener("touchmove", findScroll);
} else if (
(!scrollUp || e.type === "touchmove") &&
activeSlide.scrollTop >= diff
) {
swiper.mousewheel.enable();
swiper.allowTouchMove = true;
activeSlide.removeEventListener("wheel", findScroll);
activeSlide.removeEventListener("touchmove", findScroll);
}
};
activeSlide.addEventListener("wheel", findScroll);
activeSlide.addEventListener("touchmove", findScroll);
swiper.mousewheel.disable();
swiper.allowTouchMove = false;
}
};
基本上,通过将scrollTop设置为距范围顶部或底部1px,可以防止立即触发mousewheel.enable()调用。在原始版本中,激活时幻灯片始终从滚动高度的顶部开始,而此版本如果您向下滑动到它,则从“顶部”(技术上向下 1px)开始,如果您“向下滑动”,则从“底部”开始重新向上滑动即可。
修改自@LeTsoy的答案,
const handleScrollInside = (swiper) => {
swiper.on("slideChangeTransitionEnd", () => {
swiper.mousewheel.disable();
swiper.allowTouchMove = false;
const activeSlide = document.querySelector('.swiper-slide-active');
const hasVerticalScrollbar = activeSlide.scrollHeight > activeSlide.clientHeight;
if (hasVerticalScrollbar) {
const scrollDifferenceTop = activeSlide.scrollHeight - activeSlide.swiperSlideSize;
if (activeSlide.scrollTop === 0) activeSlide.scrollTop += 1;
if (activeSlide.scrollTop === scrollDifferenceTop) activeSlide.scrollTop -= 2;
swiper.mousewheel.disable();
swiper.allowTouchMove = false;
const scrollHandler = () => {
if (activeSlide.scrollTop <= 0 || scrollDifferenceTop - activeSlide.scrollTop <= 1 ) {
swiper.mousewheel.enable();
swiper.allowTouchMove = true;
activeSlide.removeEventListener('scroll',scrollHandler);
}
};
activeSlide.addEventListener('scroll', scrollHandler, { passive: true });
} else {
swiper.mousewheel.enable();
swiper.allowTouchMove = true;
}
})
const activeSlide = document.querySelector('.swiper-slide-active');
const hasVerticalScrollbar = activeSlide.scrollHeight > activeSlide.clientHeight;
if (hasVerticalScrollbar) {
swiper.emit('slideChangeTransitionEnd');
}
}
如果您在内部滚动方面遇到问题,请尝试将活动幻灯片移至顶部以使其接收滚动事件。 (我使用的 swiper 版本:11.x)看起来 swiper 中的所有幻灯片都从第 1 张幻灯片开始一层一层地堆叠,并且不透明度设置为 0。只有活动幻灯片的不透明度设置为 1。所以最后(第 n)张幻灯片将位于顶部,防止活动幻灯片接收滚动事件。
.swiper-slide-active{
position: relative;
z-index: 10;
}