You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Embla Carousel中拖拽式颜色选择器无法正常工作的问题

问题:Embla Carousel与ChromePicker拖拽冲突

在使用Embla Carousel时,拖拽ChromePicker颜色选择器会同时触发轮播图的拖拽行为,导致颜色选择器无法正常操作。

尝试过将<ChromePicker />包裹在带内边距的div中,并实现onPointerDown、onPointerMove、onPointerUp事件来阻止事件冒泡与默认行为,但仅在div内边距区域拖拽时有效,直接拖拽<ChromePicker />本身仍会带动轮播图移动。

复现代码

index.tsx(仅修改为传入<ChromePicker />的默认Embla Carousel)

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 = [
    // 添加ChromePicker
    <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(仅修改map函数以显示<ChromePicker />的默认Embla Carousel)

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 = {
  // 临时改为any[]以支持传入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}>
              {/* 修改为直接渲染slide内容,而非默认的索引 */}
              <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

解决方案

通过在Embla Carousel的配置项中添加watchDrag函数,判断拖拽目标是否属于ChromePicker区域,若属于则阻止轮播图的拖拽触发:

修改后的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 = [
    // 添加ChromePicker
    <ChromePicker color={hex} onChange={(color) => setHex(color.hex)} />,
    2,
    3,
    4,
    5
  ]

  // 解决方案:通过watchDrag判断拖拽目标
  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>
)

内容的提问来源于stack exchange,提问作者Milly Chaser

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 20:04:52