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和maxWidthprops限制Div宽度范围,避免拖拽过度 - 全局事件监听:拖拽开始后给window绑定
mousemove和mouseup事件,确保鼠标移出Div时仍能正常处理拖拽 - 响应式内容:内部图片和文本设置
width: 100%,会自动跟随Div宽度变化
扩展优化点
- 给手柄添加hover样式(比如加深背景色),提升交互反馈
- 拖拽时显示实时宽度提示(悬浮文本框)
- 将拖拽逻辑封装为自定义Hook,实现多组件复用
内容的提问来源于stack exchange,提问作者SKR Sama
相关产品推荐
相关产品推荐

