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

React实现拖拽边框而非角落调整Div宽度的方案求助

纯React实现Div左右边框拖拽调整宽度

以下是纯React的实现方案,无需依赖jQuery,核心通过监听鼠标事件实现拖拽逻辑,同时在悬停时显示调整手柄:

实现思路

  • 用React状态管理Div的宽度值
  • 在Div的左右两侧添加调整手柄,默认隐藏,当父Div悬停时显示
  • 监听手柄的mousedown事件触发拖拽状态;通过全局mousemove事件计算宽度变化;mouseup事件结束拖拽
  • 拖拽过程中实时更新Div的宽度,内部内容会自动适配(需确保内部元素支持响应式)

完整组件代码

import { useState, useCallback, useEffect } from 'react';

const ResizableDiv = ({ initialWidth = 400, minWidth = 200, maxWidth = 800, children }) => {
  const [width, setWidth] = useState(initialWidth);
  const [isResizingLeft, setIsResizingLeft] = useState(false);
  const [isResizingRight, setIsResizingRight] = useState(false);
  const [startX, setStartX] = useState(0);
  const [startWidth, setStartWidth] = useState(0);

  // 左侧拖拽开始事件
  const handleLeftResizeStart = useCallback((e) => {
    setIsResizingLeft(true);
    setStartX(e.clientX);
    setStartWidth(width);
    e.preventDefault(); // 阻止文本选中默认行为
  }, [width]);

  // 右侧拖拽开始事件
  const handleRightResizeStart = useCallback((e) => {
    setIsResizingRight(true);
    setStartX(e.clientX);
    setStartWidth(width);
    e.preventDefault();
  }, [width]);

  // 拖拽过程计算宽度
  const handleResize = useCallback((e) => {
    if (isResizingLeft) {
      const deltaX = startX - e.clientX;
      const newWidth = startWidth + deltaX;
      if (newWidth >= minWidth && newWidth <= maxWidth) {
        setWidth(newWidth);
      }
    } else if (isResizingRight) {
      const deltaX = e.clientX - startX;
      const newWidth = startWidth + deltaX;
      if (newWidth >= minWidth && newWidth <= maxWidth) {
        setWidth(newWidth);
      }
    }
  }, [isResizingLeft, isResizingRight, startX, startWidth, minWidth, maxWidth]);

  // 结束拖拽
  const handleResizeEnd = useCallback(() => {
    setIsResizingLeft(false);
    setIsResizingRight(false);
  }, []);

  // 全局绑定/解绑鼠标事件
  useEffect(() => {
    if (isResizingLeft || isResizingRight) {
      window.addEventListener('mousemove', handleResize);
      window.addEventListener('mouseup', handleResizeEnd);
      return () => {
        window.removeEventListener('mousemove', handleResize);
        window.removeEventListener('mouseup', handleResizeEnd);
      };
    }
  }, [isResizingLeft, isResizingRight, handleResize, handleResizeEnd]);

  return (
    <div
      className="resizable-container"
      style={{
        width: `${width}px`,
        minWidth: `${minWidth}px`,
        maxWidth: `${maxWidth}px`,
        position: 'relative',
        border: '1px solid #ccc',
        padding: '16px',
        overflow: 'hidden',
      }}
    >
      {/* 左侧调整手柄 */}
      <div
        className="resize-handle resize-handle-left"
        style={{
          position: 'absolute',
          left: '-5px',
          top: '0',
          bottom: '0',
          width: '10px',
          cursor: 'ew-resize',
          opacity: 0,
          transition: 'opacity 0.2s',
          backgroundColor: 'rgba(0, 0, 0, 0.1)',
        }}
        onMouseDown={handleLeftResizeStart}
      />
      {/* 右侧调整手柄 */}
      <div
        className="resize-handle resize-handle-right"
        style={{
          position: 'absolute',
          right: '-5px',
          top: '0',
          bottom: '0',
          width: '10px',
          cursor: 'ew-resize',
          opacity: 0,
          transition: 'opacity 0.2s',
          backgroundColor: 'rgba(0, 0, 0, 0.1)',
        }}
        onMouseDown={handleRightResizeStart}
      />
      {/* 内部内容容器 */}
      <div className="resizable-content">
        {children}
      </div>

      {/* 悬停显示手柄的样式 */}
      <style jsx>{`
        .resizable-container:hover .resize-handle {
          opacity: 1;
        }
      `}</style>
    </div>
  );
};

// 使用示例
const App = () => {
  return (
    <div style={{ padding: '20px' }}>
      <ResizableDiv initialWidth={500} minWidth={300} maxWidth={700}>
        <img src="https://picsum.photos/seed/react-resize/400/200" alt="示例图片" style={{ width: '100%', height: 'auto' }} />
        <p>这是可调整宽度的Div内部文本,拖拽左右边框可以改变容器宽度,内部内容会自动适配。</p>
      </ResizableDiv>
    </div>
  );
};

export default App;

关键细节说明

  • 手柄显示逻辑:通过父容器的:hover伪类控制手柄透明度,悬停时显示,退出时隐藏
  • 拖拽范围限制:通过minWidth和maxWidth props限制Div宽度范围,避免拖拽过度
  • 全局事件监听:拖拽开始后给window绑定mousemove和mouseup事件,确保鼠标移出Div时仍能正常处理拖拽
  • 响应式内容:内部图片和文本设置width: 100%,会自动跟随Div宽度变化

扩展优化点

  • 给手柄添加hover样式(比如加深背景色),提升交互反馈
  • 拖拽时显示实时宽度提示(悬浮文本框)
  • 将拖拽逻辑封装为自定义Hook,实现多组件复用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 20:35:30