首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >第一次滑动后未在IOS Safari上触发自定义旋转组件的Touchevents

第一次滑动后未在IOS Safari上触发自定义旋转组件的Touchevents
EN

Stack Overflow用户
提问于 2021-03-29 16:58:38
回答 1查看 514关注 0票数 0

我在React中创建了一个自定义的照片旋转组件(因为外部库太难操作,或者没有完成我希望它做的事情),您可以在移动上滑动到下一张/上一张照片。Android上一切都很好,但这只是IOS Safari。

问题

我有一页画了几个传送带的地图。地图上的第一个旋转木马工作得很好。随后的传送带将在第一张幻灯片后正确地滑动,但是一旦它过渡到第二张幻灯片,触控事件就停止了,并且它不会滑动。我想要的是像第一个旋转木马一样的旋转木马。也没有看到错误消息。请参阅视频

代码

以下是自定义组件:

代码语言:javascript
复制
import { useState, useEffect } from 'react'

const Carousel = ({ children }) => {
  const IMG_WIDTH = 400

  const [currentIndex, setCurrentIndex] = useState(0)
  const [lastTouch, setLastTouch] = useState(0)
  const [movement, setMovement] = useState(0)
  const [transitionDuration, setTransitionDuration] = useState('')
  const [transitionTimeout, setTransitionTimeout] = useState(null)
  const maxLength = children.length - 1,
    maxMovement = maxLength * IMG_WIDTH

  useEffect(() => {
    return () => {
      clearTimeout(transitionTimeout)
    }
  }, [])

  const transitionTo = (index, duration) => {
    setCurrentIndex(index)
    setMovement(index * IMG_WIDTH)
    setTransitionDuration(`${duration}s`)

    setTransitionTimeout(
      setTimeout(() => {
        setTransitionDuration('0s')
      }, duration * 100))
  }

  const handleMovementEnd = () => {
    const endPosition = movement / IMG_WIDTH
    const endPartial = endPosition % 1
    const endingIndex = endPosition - endPartial
    const deltaInteger = endingIndex - currentIndex

    let nextIndex = endingIndex

    if (deltaInteger >= 0) {
      if (endPartial >= 0.1) {
        nextIndex++
      }
    } else if (deltaInteger < 0) {
      nextIndex = currentIndex - Math.abs(deltaInteger)
      if (endPartial > 0.9) {
        nextIndex++
      }
    }

    transitionTo(nextIndex, Math.min(0.5, 1 - Math.abs(endPartial)))
  }

  const handleMovement = delta => {
    clearTimeout(transitionTimeout)

    const maxLength = children.length - 1
    let nextMovement = movement + delta

    if (nextMovement < 0) {
      nextMovement = 0
    }

    if (nextMovement > maxLength * IMG_WIDTH) {
      nextMovement = maxLength * IMG_WIDTH
    }
    setMovement(nextMovement)
    setTransitionDuration('0s')
  }

  const handleTouchStart = event => {
    setLastTouch(event.nativeEvent.touches[0].clientX)
  }

  const handleTouchMove = event => {
    const delta = lastTouch - event.nativeEvent.touches[0].clientX
    setLastTouch(event.nativeEvent.touches[0].clientX)
    handleMovement(delta)
  }

  const handleTouchEnd = () => {
    handleMovementEnd()
    setLastTouch(0)
  }

  return (
    <div
      className="main"
      style={{ width: IMG_WIDTH }}
      onTouchStart={handleTouchStart}
      onTouchMove={handleTouchMove}
      onTouchEnd={handleTouchEnd}>
      <div
        className="swiper"
        style={{
          transform: `translateX(${movement * -1}px)`,
          transitionDuration: transitionDuration
        }}>
        {children} // This is just <img /> tags
      </div>
      <div className="bullets">
        {[...Array(children.length)].map((bullet, index) => (
          <div key={`bullet-${index}`} className={`dot ${currentIndex === index && 'red-dot'}`} />
        ))}
      </div>
    </div>
  )
}

export default Carousel

下面是我使用自定义组件的代码的一部分:

代码语言:javascript
复制
return (
    <>
      <Announcement />
      <Header />

      <section className="tiles-section">
        <Title />
        {Component} // This is just a component that simply maps out the Carousel, nothing special and no extra styling
      </section>
      ...
    </>
  )

和CSS:

代码语言:javascript
复制
.main {
    overflow: hidden;
    position: relative;
    touch-action: pan-y;
}

.swiper {
    display: flex;
    overflow-x: visible;
    transition-property: transform;
    will-change: transform;
}

我所知道的/尝试过的

  • 移除旋转木马上方的部分部件(如。(标题、公告等)使幻灯片的一部分,而不是第一个幻灯片可滑动。它可以是幻灯片高度的一半,也可以是可滑动高度的1/3,这取决于我删除了多少。这不包括第一个旋转木马,它仍然工作得很好。
  • 我试过移除一堆CSS,但没起作用
  • 尝试将事件侦听器添加到“main”div中,可能我做错了什么,但一个旋转木马最后却滑动了所有的旋转木马。
  • 我认为这与我在自定义旋转木马组件中创建的触摸事件处理程序函数有关,但它们似乎工作得很好,因为在将它们更改为console.logs并手动翻译幻灯片之后,触摸事件仍然没有触发。

更新#1

我将触摸事件处理程序放入包装{child}的新div中。第二张幻灯片现在可以滑动,但是第三张幻灯片仍然是个泡影。

参考文献

这是我为定制旋转木马组件创建更多上下文的链接教程。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-04-03 06:29:02

经过几天和几个小时后,解决办法有点奇怪。我猜您需要正确地将目标设置为元素的div id。我把这个放在useEffect中,结果如下:

代码语言:javascript
复制
useEffect(() => {
    document.getElementById(id).addEventListener('touchstart', () => false, { passive: false })

    return () => {
      clearTimeout(transitionTimeout)
    }
  }, [])

请注意,id必须是唯一的,特别是如果创建了与我一样的组件的映射。否则,一个旋转木马将滑动所有的旋转木马。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66858417

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档