如果之前曾问过类似的问题,我们深表歉意。
我的问题是,当使用 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>
)
您可以利用以下配置选项,特别是 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
}
}