You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 20:01:13