React基于坐标定位元素:滚动后点击位置偏移问题求助
问题解决:页面滚动后点击定位错位
问题根源
你当前用clientX/clientY设置绝对定位元素的位置,这两个值是相对于浏览器视口的坐标。页面滚动时,文档内容相对于视口发生偏移,基于视口的坐标无法正确映射到文档的绝对位置,导致元素错位。
解决方案
推荐使用基于时间段容器的相对定位,让元素始终锚定在点击的容器区域内,不受页面滚动影响:
步骤1:给容器添加定位上下文和Ref
首先给时间段容器设置relative定位(作为绝对定位元素的父级上下文),并添加Ref用于获取容器位置:
import { useRef } from 'react'; // 组件内定义Ref const timeSlotContainerRef = useRef<HTMLDivElement>(null); // 修改容器的className和添加Ref <div className="flex flex-col h-[93%] relative" ref={timeSlotContainerRef} onClick={handlePosClick}> {renderTimeSlots()} </div>
步骤2:计算相对于容器的点击位置
修改handlePosClick,计算点击位置相对于容器的偏移量,而不是直接用视口坐标:
const handlePosClick = (e: React.MouseEvent<HTMLDivElement>) => { if (!timeSlotContainerRef.current) return; // 获取容器在视口中的边界信息 const containerRect = timeSlotContainerRef.current.getBoundingClientRect(); // 计算点击位置相对于容器左上角的偏移 const relativeLeft = e.clientX - containerRect.left; const relativeTop = e.clientY - containerRect.top - 20; // 保留原有的-20像素偏移 setTimeSlotItems([...timeSlotItems, { date: currentSelectedDate, div: ( <div onClick={handleOpen} className="w-[20%] h-[60px] bg-red-400 rounded-[1rem] absolute cursor-pointer" style={{ left: `${relativeLeft}px`, top: `${relativeTop}px` }} ></div> ) }]) }
步骤3:将红色元素移到容器内部
把红色div的渲染逻辑放到时间段容器内,确保它的绝对定位是相对于容器的:
<> <div className="w-[72vw] -mr-[18vw] -mt-3 shadow-[0_3px_10px_rgb(0,0,0,0.2)] pl-5 pt-3 ml-5"> <p className="text-black font-bold">{moment(currentSelectedDate.fullDate).subtract(1, 'day').format('ddd DD MMMM YYYY')}</p> <div className="flex flex-col h-[93%] relative" ref={timeSlotContainerRef} onClick={handlePosClick}> {renderTimeSlots()} {/* 红色元素放在容器内 */} {timeSlotItems.map((item: any) => { if (item.date === currentSelectedDate) return item.div })} </div> </div> </>
可选方案:改用文档坐标(仅适合元素固定在文档位置)
如果希望元素固定在文档的点击位置(滚动页面时元素不跟随视口),可以直接用pageX/pageY(相对于文档顶部的坐标)替换clientX/clientY:
const handlePosClick = (e: React.MouseEvent<HTMLDivElement>) => { setTimeSlotItems([...timeSlotItems, { date: currentSelectedDate, div: ( <div onClick={handleOpen} className="w-[20%] h-[60px] bg-red-400 rounded-[1rem] absolute cursor-pointer" style={{ left: `${e.pageX}px`, top: `${e.pageY - 20}px` }} ></div> ) }]) }
内容的提问来源于stack exchange,提问作者ImDarkk
相关产品推荐
相关产品推荐

