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

基于React-rnd实现拖拽调整后列重排的方案咨询

React-Rnd 2x2网格拖拽缩放自动布局示例

下面是一个贴合需求的简易实现,核心通过状态管理控件的位置与尺寸,在拖拽/缩放后自动调整布局,填补空出的空间:

import { useState, useEffect } from 'react';
import { Rnd } from 'react-rnd';

// 模拟权限控制:这里可以替换成实际的权限判断逻辑
const hasAccess = {
  item1: true,
  item2: true,
  item3: false, // 隐藏第三个控件
  item4: true,
};

const GridRndDemo = () => {
  // 初始化每个控件的位置、尺寸(基于2x2网格,每列/行占50%)
  const [items, setItems] = useState([
    { id: 'item1', x: 0, y: 0, width: '50%', height: '50%', show: hasAccess.item1 },
    { id: 'item2', x: '50%', y: 0, width: '50%', height: '50%', show: hasAccess.item2 },
    { id: 'item3', x: 0, y: '50%', width: '50%', height: '50%', show: hasAccess.item3 },
    { id: 'item4', x: '50%', y: '50%', width: '50%', height: '50%', show: hasAccess.item4 },
  ]);

  // 调整布局:当控件尺寸变化后,重新排列控件填补空白
  const adjustLayout = (updatedItem) => {
    setItems(prevItems => {
      // 先更新当前变化的控件
      const updatedItems = prevItems.map(item => 
        item.id === updatedItem.id ? updatedItem : item
      );
      // 过滤出需要显示的控件
      const visibleItems = updatedItems.filter(item => item.show);
      if (visibleItems.length <= 1) return updatedItems;

      // 按行分组,重新计算位置
      let currentX = 0;
      let currentY = 0;
      const rowHeight = '50%';
      const containerWidth = 100; // 用百分比数值计算,方便判断

      return updatedItems.map(item => {
        if (!item.show) return item;

        // 计算当前控件的宽度数值(去掉%)
        const itemWidth = parseInt(item.width);
        // 如果当前行剩余空间不够,移到下一行
        if (currentX + itemWidth > containerWidth) {
          currentX = 0;
          currentY = currentY === 0 ? 50 : 0;
        }

        const newItem = { ...item, x: `${currentX}%`, y: `${currentY}%` };
        currentX += itemWidth;
        return newItem;
      });
    });
  };

  // 处理缩放事件
  const handleResize = (e, direction, ref, delta, position, size) => {
    const updatedItem = {
      ...items.find(i => i.id === ref.id),
      width: `${size.width}%`,
      height: `${size.height}%`,
      x: `${position.x}%`,
      y: `${position.y}%`,
    };
    adjustLayout(updatedItem);
  };

  // 处理拖拽事件
  const handleDragStop = (e, d) => {
    const updatedItem = {
      ...items.find(i => i.id === e.target.id),
      x: `${d.x}%`,
      y: `${d.y}%`,
    };
    adjustLayout(updatedItem);
  };

  return (
    <div style={{ width: '100vw', height: '100vh', position: 'relative', border: '1px solid #ccc' }}>
      {items.map(item => (
        item.show && (
          <Rnd
            key={item.id}
            id={item.id}
            size={{ width: item.width, height: item.height }}
            position={{ x: item.x, y: item.y }}
            bounds="parent"
            onResizeStop={handleResize}
            onDragStop={handleDragStop}
            style={{ border: '2px solid #4285f4', backgroundColor: 'rgba(66, 133, 244, 0.1)' }}
          >
            <div style={{ padding: '1rem' }}>{item.id}</div>
          </Rnd>
        )
      ))}
    </div>
  );
};

export default GridRndDemo;

关键逻辑说明

  • 用items状态存储每个控件的位置、尺寸和显示状态,可直接通过hasAccess对象控制哪些控件显示
  • adjustLayout函数会在控件拖拽/缩放后触发,遍历可见控件,自动计算每行剩余空间,把放不下的控件移到下一行并填充空白
  • 网格基础单位按百分比设置(每列/行占50%),可根据实际需求调整容器尺寸和单位

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 22:40:02