在项目中,设计说想做个面板,其宽度随鼠标拖拽而变化,有最大最小值。基于这个小功能封装一个可拖拽组件,在需要的地方引入即可。
思路
这里只是实现x方向的拖拽,y轴拖拽思路差不多。
既然是鼠标操作,那肯定得监听鼠标事件,当鼠标按下(mouseDown)时,监听mouseMove事件和mouseUp事件,就是鼠标移动和抬起操作。然后计算出鼠标移动的宽度 = 元素现在的x坐标(clientX) - 起始坐标;然后把移动的宽度通过onChange函数返回给父组件,父组件改变自身的宽度。
代码示例
组件代码如下:
javascript
import React, { useRef, useState, useEffect } from 'react';
interface DragLineProps {
style?: any; // 自定义样式
className?: string; // 样式类名
onChange: (width: number, height:number) => void; // 宽高变化函数
}
const DragLine: React.FC<DragLineProps> = (props) => {
const {style, className, onChange } = props;
const containerRef = useRef<HTMLDivElement>(null);
const [isDragging, setIsDragging] = useState(false);
const initialMouseX = useRef(0); // 初始x值
const initialMouseY = useRef(0); // 初始Y值
useEffect(() => {
const handleMouseMove = (event: MouseEvent) => {
if (isDragging && containerRef.current) {
const deltaX = event.clientX - initialMouseX?.current;
const deltaY = event.clientY - initialMouseY?.current;
// 调用父组件函数,传回移动的宽度或高度
onChange(deltaX, deltaY)
}
};
const handleMouseUp = () => {
setIsDragging(false);
};
// 添加鼠标移动和抬起事件
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
return () => {
// 记得清除监听事件
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
};
}, [isDragging, initialMouseX, initialMouseY, onChange]);
/** 监听鼠标按下事件 改变初始值 **/
const handleMouseDown = (event: React.MouseEvent<HTMLDivElement>) => {
event.preventDefault();
setIsDragging(true);
initialMouseX.current = event.clientX;
initialMouseY.current = event.clientY;
};
return (
<div
ref={containerRef}
className={className}
style={style}
onMouseDown={handleMouseDown}
/>
);
};
export default DragLine;
使用:
我这里是左侧面板可拖拽宽度,当然也可以是右侧面板,如需上下拖动,可以先定义高度,然后通过子组件调用handleChange传回的offsetY操作即可。
javascript
import React, { useState } from 'react';
import DragLine from '../../components/DragBox';
import './style.less';
const maxWidth = 300;
const minWidth = 100;
const App: React.FC = () => {
const [width, setWidth] = useState(200);
const handleChange = (offsetX: number, offsetY:number) => {
const current = offsetX+ width;
const newWidth = current > maxWidth ? maxWidth : current < minWidth ? minWidth : current;
setWidth(newWidth);
};
return (
<div className='DragWrapperRoot'>
<div style={{width}} className='dragBox'>
拖拽右侧边框改变盒子大小
</div>
<DragLine onChange={handleChange} className="width-drag" style={{left: width}}/>
</div>
);
};
export default App;
less文件:
javascript
.DragWrapperRoot{
position: relative;
display: flex;
height: 80%;
.dragBox{
position: relative;
border-right: 1px solid #999;
height: 100%;
}
.width-drag{
position: absolute;
cursor: ew-resize; // 鼠标悬停双箭头样式
top: 0;
bottom: 0;
width: 10px;
background: transparent;
}
}
总结
- 创建一个
DragLine
组件,接受一个onChange
函数作为参数,该函数用于接收拖拽宽度的更新。 - 使用
useRef
钩子来获取<div>
容器的引用,以便后续操作。 - 使用
useState
钩子来追踪拖拽状态,通过isDragging
变量表示是否正在拖拽。 - 使用
useEffect
钩子来添加事件监听器,以便在鼠标移动和释放的过程中执行相应的操作。 - 在
handleMouseMove
回调函数中,根据鼠标位置和容器的左边界计算新的宽度和高度,并通过onChange
函数将新的宽度传递给父组件。 - 在
handleMouseUp
回调函数中,将拖拽状态设置为false
,表示拖拽结束。 - 在
handleMouseDown
回调函数中,将拖拽状态设置为true
,表示开始拖拽。 - 将
handleMouseDown
函数绑定到容器的onMouseDown
事件上,以便在鼠标按下时触发拖拽行为。 - 在组件的返回部分,使用
ref
将容器的引用与<div>
元素关联起来。 - 通过添加适当的CSS样式,使得容器显示为竖线,并具有适当的拖拽光标效果。
DragLine`组件的思路是利用事件监听器来捕获鼠标的拖拽行为,计算拖拽宽度,并通过回调函数将更新后的宽度和高度传递给父组件。这样可以实现通过鼠标拖拽来改变容器宽度或者高度的功能。