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
相关产品推荐
相关产品推荐

