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

实现点击生成随机盒子,无剩余空间时禁用按钮功能

解决方案

核心思路

通过碰撞检测判断容器是否还能容纳最小尺寸的盒子,动态控制按钮的禁用状态,同时监听窗口尺寸变化,确保容器大小改变时状态同步更新。

修改步骤及代码实现

  1. 添加按钮禁用状态及容器尺寸监听
  2. 实现碰撞检测函数判断是否可添加新盒子
  3. 绑定按钮禁用属性

修改后的完整代码:

import { useState, useRef, useEffect } from "react";
import "./styles.css";

export default function App() {
  const [boxes, setBoxes] = useState([]);
  const [isButtonDisabled, setIsButtonDisabled] = useState(false);
  const containerRef = useRef(null);

  // 判断是否还能添加新盒子:尝试生成10次最小尺寸盒子的位置,检查是否与现有盒子碰撞
  const canAddBox = () => {
    const container = containerRef.current;
    if (!container) return true;
    const containerWidth = container.clientWidth;
    const containerHeight = container.clientHeight;
    const minBoxSize = 50; // 对应生成盒子的最小尺寸

    // 容器本身放不下最小盒子,直接返回false
    if (containerWidth < minBoxSize || containerHeight < minBoxSize) {
      return false;
    }

    // 尝试10次随机位置,避免单次随机位置不佳导致误判
    for (let i = 0; i < 10; i++) {
      const top = Math.floor(Math.random() * (containerHeight - minBoxSize));
      const left = Math.floor(Math.random() * (containerWidth - minBoxSize));
      const newBoxRight = left + minBoxSize;
      const newBoxBottom = top + minBoxSize;

      // 检查与现有盒子是否碰撞
      let hasOverlap = false;
      for (const box of boxes) {
        const boxRight = box.left + box.size;
        const boxBottom = box.top + box.size;
        // 矩形碰撞检测规则:不满足"完全分离"则为重叠
        if (!(left >= boxRight || newBoxRight <= box.left || top >= boxBottom || newBoxBottom <= box.top)) {
          hasOverlap = true;
          break;
        }
      }

      if (!hasOverlap) return true;
    }

    // 10次尝试都找不到合适位置,判定无法添加
    return false;
  };

  // 生成随机盒子
  const generateBox = () => {
    const container = containerRef.current;
    if (!container) return;
    const maxSize = Math.min(container.clientWidth, container.clientHeight) / 4;
    const size = Math.floor(Math.random() * maxSize) + 50;
    const top = Math.floor(Math.random() * (container.clientHeight - size));
    const left = Math.floor(Math.random() * (container.clientWidth - size));
    const color = `#${Math.floor(Math.random() * 16777215).toString(16)}`;
    setBoxes([...boxes, { size, top, left, color }]);
  };

  // 监听盒子列表变化和窗口resize,更新按钮禁用状态
  useEffect(() => {
    const updateButtonStatus = () => {
      setIsButtonDisabled(!canAddBox());
    };

    updateButtonStatus();
    window.addEventListener("resize", updateButtonStatus);
    return () => window.removeEventListener("resize", updateButtonStatus);
  }, [boxes]);

  return (
    <div className="App">
      <button onClick={generateBox} disabled={isButtonDisabled}>
        生成盒子
      </button>
      <div ref={containerRef} className="container">
        {boxes.map((box, index) => (
          <div
            key={index}
            className="box"
            style={{
              width: `${box.size}px`,
              height: `${box.size}px`,
              top: `${box.top}px`,
              left: `${box.left}px`,
              backgroundColor: box.color
            }}
          />
        ))}
      </div>
    </div>
  );
}

关键细节说明

  • 碰撞检测逻辑:通过矩形分离轴定理判断新盒子与现有盒子是否重叠,确保判断准确性。
  • 多次随机尝试:避免单次随机位置刚好落在已占用区域,导致误判容器无剩余空间。
  • 窗口resize监听:容器尺寸变化时重新计算可添加状态,适配窗口大小调整场景。

内容的提问来源于stack exchange,提问作者Achi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 09:30:57