React 实现鼠标水平滚动组件
实现要点
- 页面布局
- 监听鼠标滚动事件
- 计算滚动位置进行对齐
实现步骤
页面布局
- 父元素采用
flex
布局且设置flex-wrap: nowrap
使其子元素可以完全展开 - 子元素设置
flex-shrink: 0
使其能够不进行自适应缩小
事件监听
- 通过调用
event.preventDefault()
阻止浏览器默认行为 - 使用
useRef()
获取父元素的DOM元素,使用.current
获取dom对象进行操作 - 设置父元素的
wheel
鼠标滚动监听事件,并进行对应的计算
注意事项
- 使用react
onWheel
事件进行阻止默认行为无效,且会提示报错,所以使用ref获取dom元素代替 - react 事件是合成事件且不持久,不可异步传入
元素滚动
元素可以通过scrollTo()方法进行滚动
Tips:
- offsetWidth/offsetHeight 获取元素宽高
- scrollLeft/Top 获取偏移位置
- scrollWidth 获取滚动宽度
参考代码
import { createStyles, withStyles } from \'@material-ui/core/styles\'import { SitePropsType } from \'components/base/Site\'
import { useEffect, useRef } from \'react\'
const styles = createStyles({
root: {
overflowX: \'auto\',
},
container: {
display: \'flex\',
flexWrap: \'nowrap\',
overflowX: \'auto\',
},
item: {
height: \'300px\',
width: \'100%\',
backgroundColor: \'#f0f0f0\',
border: \'1px solid #333333\',
flexShrink: 0,
// \'&:hover\': {
// cursor: \'pointer\',
// },
},
indicator: {},
})
interface SiteSwiperProps {
classes?: {
root: string
container: string
item: string
indicator: string
}
sites: SitePropsType[]
row?: number
}
/**
* 计算滚动位置
* @param currentScrollLeft
* @param scrollElWith
*/
const computeScroll = (
currentScrollLeft: number,
scrollElWith: number
): number => {
// 判断滚动偏移是否满足滚动要求
console.log(\'current scroll left:\', currentScrollLeft)
const index = Math.round(currentScrollLeft / scrollElWith)
return scrollElWith * index
}
function SiteSwiper({ classes, sites, row = 3 }: SiteSwiperProps): JSX.Element {
const containerRef = useRef(null)
const timer = useRef(null)
useEffect(() => {
console.log(\'current ref:\', containerRef)
containerRef.current.addEventListener(\'wheel\', (e) => {
console.log(\'mouse wheel event:\', e)
// 阻止原生滚动事件
e.preventDefault()
// 获取滚动位置
let scrollLeft = containerRef.current.scrollLeft
const scrollTotalWidth = containerRef.current.scrollWidth
const scrollItemWidth = containerRef.current.offsetWidth
// 获取容器的宽度
console.log(
\'current container:\',
containerRef.current.offsetWidth,
e.deltaY
)
// 即时水平滚动偏移值
const bufferOffset = 70
const scrollBehavior = \'smooth\'
let offset = scrollLeft + e.deltaY * 4 // 放大偏移倍数
if (offset >= scrollTotalWidth - scrollItemWidth + bufferOffset) {
// 到达最后元素
offset = offset - scrollTotalWidth - bufferOffset
// scrollBehavior = \'auto\'
} else if (offset + bufferOffset < 0) {
// 达到第一元素
offset = scrollTotalWidth + offset - bufferOffset
// scrollBehavior = \'auto\'
} else {
// 其它情况
}
console.log(\'offset y at time:\', scrollLeft, offset)
containerRef.current.scrollTo({
top: 0,
left: offset,
behavior: scrollBehavior,
})
// 防抖
if (timer.current) {
clearTimeout(timer.current)
}
timer.current = setTimeout(() => {
// 计算滚动最后的位置进行位置矫正
console.log(\'TIME OUT: starting position correct...\')
// 计算是否滚动
scrollLeft = computeScroll(offset, scrollItemWidth)
containerRef.current.scrollTo({
top: 0,
left: scrollLeft,
behavior: \'smooth\',
})
}, 700)
})
})
return (
<div className={classes.root} id="swiper-container">
{/* Content */}
<div
className={classes.container}
// onScroll={handleMouseScroll}
// onMouseOver={handleMouseOver}
// onWheel={handleWheel}
ref={containerRef}
>
{[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((item) => (
<div className={`${classes.item} swiper-item`} key={item}>
{item}
</div>
))}
</div>
{/* Indicator */}
<div className={classes.indicator}></div>
</div>
)
}
export default withStyles(styles)(SiteSwiper)
以上是 React 实现鼠标水平滚动组件 的全部内容, 来源链接: utcz.com/z/383769.html