Embla 轮播中的可拖动容器(颜色选择器)无法按预期工作

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

如果之前曾问过类似的问题,我们深表歉意。

我的问题是,当使用 Embla Carousel 并实现颜色选择器(单独或包装在 div 中)时,拖动颜色选择器无法按预期工作,因为它也会拖动旋转木马。

我实现了一个简单的代码沙箱供大家参考。

最小化复制

在我自己的代码中,我尝试将

<ChromePicker />
包装在 div 中(在 div 上应用了填充)。并实现 onPointerDown、onPointerMove 和 onPointerUp 来 stopPropagation 和 PreventDefault。

所以这仅适用于 div,如果我尝试在 div 内部(在填充区域上)拖动,它不会拖动轮播。但拖动

<ChromePicker />
仍然会使轮播移动。

感谢指南@Phil,很抱歉没有包含代码。以下来自沙盒

index.tsx
- 默认 Embla Carousel,稍作更改即可传入
<ChromePicker />

import React, { useState } from 'react'
import ReactDOM from 'react-dom/client'
import EmblaCarousel from './EmblaCarousel'
import { EmblaOptionsType } from 'embla-carousel'
import Header from './Header'
import Footer from './Footer'
import '../css/base.css'
import '../css/sandbox.css'
import '../css/embla.css'
import { ChromePicker } from 'react-color'

const OPTIONS: EmblaOptionsType = {}

const App: React.FC = () => {
  const [hex, setHex] = useState<string>('#000000')
  const SLIDES = [
    // Added ChromePicker here
    <ChromePicker color={hex} onChange={(color) => setHex(color.hex)} />,
    2,
    3,
    4,
    5
  ]

  return (
    <>
      <Header />
      <EmblaCarousel slides={SLIDES} options={OPTIONS} />
      <Footer />
    </>
  )
}

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
)

EmblaCarousel.tsx
- 默认 Embla 轮播,对
.map
功能略有更改以显示
<ChromePicker/ >

import React from 'react'
import { EmblaOptionsType } from 'embla-carousel'
import useEmblaCarousel from 'embla-carousel-react'
import AutoHeight from 'embla-carousel-auto-height'
import {
  NextButton,
  PrevButton,
  usePrevNextButtons
} from './EmblaCarouselArrowButtons'
import { DotButton, useDotButton } from './EmblaCarouselDotButton'

type PropType = {
  // Changed this to any[] for now to allow passing in ChromePicker
  slides: any[]
  options?: EmblaOptionsType
}

const EmblaCarousel: React.FC<PropType> = (props) => {
  const { slides, options } = props
  const [emblaRef, emblaApi] = useEmblaCarousel(options, [AutoHeight()])

  const { selectedIndex, scrollSnaps, onDotButtonClick } =
    useDotButton(emblaApi)

  const {
    prevBtnDisabled,
    nextBtnDisabled,
    onPrevButtonClick,
    onNextButtonClick
  } = usePrevNextButtons(emblaApi)

  return (
    <div className="embla">
      <div className="embla__viewport" ref={emblaRef}>
        <div className="embla__container">
          {slides.map((slide, index) => (
            <div className="embla__slide" key={index}>
              {/* Edited to show slide instead of generating index as per default of Embla */}
              <div className="embla__slide__number">{slide}</div>
            </div>
          ))}
        </div>
      </div>

      <div className="embla__controls">
        <div className="embla__buttons">
          <PrevButton onClick={onPrevButtonClick} disabled={prevBtnDisabled} />
          <NextButton onClick={onNextButtonClick} disabled={nextBtnDisabled} />
        </div>

        <div className="embla__dots">
          {scrollSnaps.map((_, index) => (
            <DotButton
              key={index}
              onClick={() => onDotButtonClick(index)}
              className={'embla__dot'.concat(
                index === selectedIndex ? ' embla__dot--selected' : ''
              )}
            />
          ))}
        </div>
      </div>
    </div>
  )
}

export default EmblaCarousel

已编辑 谢谢@Kostas Minaidis 提供的解决方案!

解决方案已添加

watchDrag
OPTIONS
-
index.tsx

import React, { useState } from 'react'
import ReactDOM from 'react-dom/client'
import EmblaCarousel from './EmblaCarousel'
import { EmblaOptionsType } from 'embla-carousel'
import Header from './Header'
import Footer from './Footer'
import '../css/base.css'
import '../css/sandbox.css'
import '../css/embla.css'
import { ChromePicker } from 'react-color'

const App: React.FC = () => {
  const [hex, setHex] = useState<string>('#000000')
  const SLIDES = [
    // Added ChromePicker here
    <ChromePicker color={hex} onChange={(color) => setHex(color.hex)} />,
    2,
    3,
    4,
    5
  ]

  // Solution from @Kostas Minaidis works perfectly!
  const OPTIONS: EmblaOptionsType = {
    watchDrag: (_, event) => {
      const target = event.target as HTMLElement
      if (
        target.classList.contains('chrome-picker') ||
        target.closest('.chrome-picker')
      ) {
        return false
      }
      return true
    }
  }

  return (
    <>
      <Header />
      <EmblaCarousel slides={SLIDES} options={OPTIONS} />
      <Footer />
    </>
  )
}

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
)

reactjs react-color embla-carousel
1个回答
1
投票

您可以利用以下配置选项,特别是 EmblaCarousel 提供的

watchdrag
选项,并在拖动目标是容器 div 时启用拖动(返回 true),否则禁用拖动(颜色选择器内的任何位置)。

const OPTIONS: EmblaOptionsType = {
  watchDrag: (_, event) => {
    if (event.target.classList.contains('embla__slide__number')) {
      return true; // <= Will enabled dragging
    }
    return false; // <= Will disable dragging
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.