鼠标滚轮时,垂直滑动滑块内嵌套滚动:true

问题描述 投票:0回答:3

我有一个垂直滑块,我使用滑动器来浏览幻灯片。

每个 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);
javascript html css scroll swiper.js
3个回答
2
投票

啊伙计们!非常感谢您的意见,我也遇到了同样的问题。但您的解决方案在移动设备上不适用于我。 所以我根据你的输入尝试了一些东西,并进行了一些修改。 所以这是我的: (我在堆栈溢出上的第一篇文章)

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;
        }
      });
    }
  })
}

0
投票

也遇到了这个问题,@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)开始,如果您“向下滑动”,则从“底部”开始重新向上滑动即可。


0
投票

修改自@LeTsoy的答案,

  1. 主要变化是随着滚动条滑动时触发这个逻辑 是第一张幻灯片。 SlideChangeTransitionEnd 事件不会发生的地方 触发,特别是当启用 HashNavigation 时。
  2. 首先禁用鼠标滚轮和allowTouchMove,以允许内部滚动正常工作
  3. 移除滚动事件监听以避免事件监听累积
  4. 添加了 {passive:true} 以提高性能(可选)

    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;
}
© www.soinside.com 2019 - 2024. All rights reserved.