微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

ReactJs 轮播 - 如何在滑动后强制项目捕捉?

如何解决ReactJs 轮播 - 如何在滑动后强制项目捕捉?

我正在构建一个 react carousel 并设置了基本的应用程序。它是一个在移动设备上跟随你的手指的滑块,基本上是一个带有溢出的 flexBox:滚动。按钮通过将容器滚动(项目索引 * 项目的宽度)次来工作,因此如果我滚动到项目 #3,它将从起始位置滚动项目宽度的 300%。

代码如下:

function Carousel(props) {
    const {children} = props
    const [index,setIndex] = useState(0)
    const [length,setLength] = useState(children.length)
    const [touchPosition,setTouchPosition] = useState(null)
    const [movement,setMovement] = useState(0) // saves the distance swiped


    useEffect(() => {
        setLength(children.length)
    },[children])


    const next = () => {
        if (index < (length-1))  {
            setIndex(prevstate => prevstate + 1)
        }
        // sets the index to next if you are not on the last slide
    }

    const prevIoUs = () => {
        if (index > 0) {
            setIndex(prevstate => prevstate - 1)
        }
        // sets the index to be the prevIoUs if you are further than first slide
    }

    const handletouchStart = (e) => {
        const touchDown = e.touches[0].clientX
        setTouchPosition(touchDown)
        // saves the touch position on touch start
    }

    const handletouchEnd = (e) => {
        const touchDown = touchPosition

        if (touchDown === null) {
            return
        }

        const currentTouch = e.changedtouches[0].clientX
        const diff = touchDown - currentTouch

        console.log(diff) // for testing
        setMovement(diff)

        if (diff > 5) {
            setTimeout(() =>  next(),100)
        } 
        if (diff < -5) {
            setTimeout(() =>  prevIoUs(),100)
        }
        setTouchPosition(null)
        // compares the starting and ending touch positions,calculates the difference
    }

    

    // to test the distance swiped
    const transformMultiplier =() => {
        let mu = (movement / window.innerWidth) * 100
        console.log(`m = ${mu}`)
    }

    useEffect(()=>{
        transformMultiplier()
    },[movement])

  

    return (
        <div className="carousel-container">
            <div className="carousel-wrapper" 
            onTouchStart={handletouchStart}
            onTouchEnd={handletouchEnd}

            > 
               { index > 0 && <button className="left-arrow" onClick={prevIoUs}>
                &lt;
                </button> }
                <div className="carousel-content-wrapper">
               { index < children.length -1 &&    <button className="right-arrow" onClick={next}>
                    &gt;
                </button>}
                {/* the sliding is done by the translateX below. it translates by (100% of the slides * the index of the slide) from the starting position.  */}
                    <div className="carousel-content"
                    style={{transform: `translateX(-${index * (window.innerWidth > 480 ? 100 : (100 - (movement / window.innerWidth) * 100))}%)`}}
                    >
                        { children}
                    </div>
                </div>
            </div>
        </div>
    )
}
.carousel-container {
    width: 100vw;
    display: flex;
    flex-direction: column;
}

.carousel-wrapper {
    display: flex;
    width: 100%;
    position: relative;
}

.carousel-content-wrapper {
    overflow: scroll;
    -webkit-overflow-scrolling: auto;
    width: 100%;
    height: 100%;
    -ms-overflow-style: none;  /* hide scrollbar in IE and Edge */
    scrollbar-width: none;  /* hide scrollbar in Firefox */
}

.carousel-content {
    display: flex;
    transition: all 250ms linear;
    -ms-overflow-style: none;  /* hide scrollbar in IE and Edge */
    scrollbar-width: none;  /* hide scrollbar in Firefox */
}

.carousel-content::-webkit-scrollbar,.carousel-content::-webkit-scrollbar {
    display: none;
}
.carousel-content-wrapper::-webkit-scrollbar,.carousel-content::-webkit-scrollbar {
    display: none;
}

.carousel-content > * {
    width: 100%;
    flex-shrink: 0;
    flex-grow: 1;
}

.left-arrow,.right-arrow {
    position: absolute;
    z-index: 1;
    top: 50%;
    transform: translateY(-50%);
    width: 48px;
    height: 48px;
    border-radius: 24px;
    background-color: white;
    border: 1px solid #ddd;
}
.left-arrow {
    left: 24px;
}

.right-arrow {
    right: 24px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

我以前在手机上滑动时,滑块会按滑动量+认过渡量进行过渡。我试图通过尝试从过渡量中减去滑动所占屏幕的百分比来解决这个问题,所以如果我滑动了 15% 的屏幕,则幻灯片应该过渡剩余的 85%。

问题:

  1. 我尝试将滑动移动量设置为状态值“移动”,这似乎引起了问题,并且在每次滑动期间都无法正确更新。所以有时滑块会使用上一次滑动的“移动”状态。
  2. 移动设备上的惯性滚动使滑动变得不可预测。我无法使用我在网上找到的一些方法将其关闭

如果有人能看一下代码,并指出我应该如何尝试解决这些问题,那就太好了。或者更好的是,如果有人知道一种不那么卡顿的方法,可以让这种轮播快速切换到下一个/上一个项目同时保持手指跟随滚动,那将是完美的。

我知道这并不理想,但是 SO 代码段编辑器给了我一个无法解释的错误,所以如果有人想在实际中使用它,这里是代码和框:https://codesandbox.io/s/hardcore-goodall-usspz?file=/src/carousel.js&resolutionWidth=320&resolutionHeight=675

解决方法

用于在父容器上滚动使用,您拥有下一个样式的所有图像 >>

 scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  display: flex;
  overflow-x: scroll;

然后对于每张幻灯片,父容器的子容器每个这种样式

scroll-snap-align: start;

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。