React中获取CSS值的方法及动态获取滑块初始宽度的实现
动态获取滑块外层容器宽度作为初始宽度的解决方案
要自动获取外层包裹div的宽度作为initialSliderWidth,不用硬编码数值,可按以下步骤修改代码:
1. 给外层容器添加Ref
为最外层的div创建一个ref,用来获取对应的DOM元素:
const containerRef = useRef<HTMLDivElement>(null);
2. 用状态存储动态宽度并自动更新
通过useState保存初始宽度,结合useEffect在组件挂载时获取容器实际宽度,同时监听窗口resize事件,确保窗口大小变化时宽度同步更新:
const [initialSliderWidth, setInitialSliderWidth] = useState<number>(0); useEffect(() => { const updateWidth = () => { if (containerRef.current) { // 直接获取容器像素宽度,也可以用numifyStyles处理getComputedStyle的结果 setInitialSliderWidth(containerRef.current.offsetWidth); } }; // 组件挂载时执行一次 updateWidth(); // 监听窗口resize事件更新宽度 window.addEventListener('resize', updateWidth); // 组件卸载时移除监听 return () => window.removeEventListener('resize', updateWidth); }, []);
3. 修复类型断言
把原来的as any替换为正确的HTML元素类型,提升代码类型安全性:
const slider = useRef<HTMLDivElement>(null); const circle = useRef<HTMLDivElement>(null);
4. 替换硬编码值
移除原来硬编码的const initialSliderWidth = 400;,直接使用状态中的initialSliderWidth即可,同时在关键逻辑处增加宽度非零判断,避免未初始化时的异常。
修改后的完整代码
import { useState, useRef, useEffect } from 'react'; const SliderComponent = (props: Props) => { const context = useNotUndefinedContext(AppContext); // 新增外层容器ref,修复类型断言 const containerRef = useRef<HTMLDivElement>(null); const slider = useRef<HTMLDivElement>(null); const circle = useRef<HTMLDivElement>(null); let initialMouseX: number; // 用状态存储动态获取的初始宽度 const [initialSliderWidth, setInitialSliderWidth] = useState<number>(0); let sliderWidth: number; let offset: number = -1; useEffect(() => { const updateWidth = () => { if (containerRef.current) { // 此处也可替换为 numifyStyles(window.getComputedStyle(containerRef.current).width) setInitialSliderWidth(containerRef.current.offsetWidth); } }; updateWidth(); window.addEventListener('resize', updateWidth); return () => window.removeEventListener('resize', updateWidth); }, []); const handleMouseMove = (mouseMoveEvent: MouseEvent) => { // 确保初始宽度已获取到再执行逻辑 if (initialSliderWidth === 0) return; const movedMouseX: number = mouseMoveEvent.clientX; let distanceMouseMovedX: number = -(movedMouseX - initialMouseX); const numifiedSliderWidth: number = sliderWidth; const newWidth: number = numifiedSliderWidth - distanceMouseMovedX; if (newWidth > initialSliderWidth || newWidth < 10) { return; } const newLength = Math.round((newWidth / initialSliderWidth) * 10); context.setPasswordLength(newLength !== 0 ? newLength : 1); if (slider.current) { slider.current.style.width = `${newWidth}px`; } if (circle.current) { circle.current.style.right = `${distanceMouseMovedX + offset}px`; } }; const handleMouseDown = (mouseDownEvent: React.MouseEvent) => { mouseDownEvent.preventDefault(); initialMouseX = mouseDownEvent.clientX; if (slider.current) { sliderWidth = numifyStyles(window.getComputedStyle(slider.current).width); } if (circle.current) { offset = numifyStyles(circle.current.style.right); circle.current.classList.remove("bg-grey-light"); circle.current.classList.add( "bg-grey-dark", "border-solid", "border-coral", "border-2" ); } window.addEventListener("mousemove", handleMouseMove); window.addEventListener( "mouseup", function handleMouseUp() { window.removeEventListener("mousemove", handleMouseMove); if (circle.current) { circle.current.classList.remove( "bg-grey-dark", "border-solid", "border-coral", "border-2" ); circle.current.classList.add("bg-grey-light"); } }, { once: true } ); }; return ( <div ref={containerRef} className="block h-[10px] bg-black mt-[32px] relative"> <div ref={slider} className="block h-[10px] bg-coral w-full h-full absolute"></div> <div ref={circle} onMouseDown={handleMouseDown} className="absolute appearance-none bg-grey-light rounded-full w-[28px] h-[28px] inline-block align-middle -right-1 -translate-y-[9px]"></div> </div> ); }; export default SliderComponent;
关键说明
offsetWidth可以直接获取元素的像素宽度,比getComputedStyle更简洁;如果习惯使用numifyStyles,可替换为numifyStyles(window.getComputedStyle(containerRef.current).width)- 监听窗口resize事件是为了适配窗口大小变化的场景,确保初始宽度始终与容器实际宽度一致
- 修复类型断言后,代码的类型安全性更高,避免潜在的DOM操作错误
- 在
handleMouseMove中增加initialSliderWidth === 0的判断,防止组件未完成初始化就执行逻辑导致异常
内容的提问来源于stack exchange,提问作者meg hidey
相关产品推荐
相关产品推荐

