可视化搭建的项目要求元素能够像作图软件同样随意的拖动改变大小 那怎么实现这个功能呢?先来一个简单的版本吧?javascript
点击进入github的demo地址,欢迎star github.com/songxuecc/R…java
const SimpleDemo = () => {
const [style, setState] = React.useState({ width: 250, height: 120 });
const origin = React.useRef(null);
// 鼠标移动 计算宽高并更新元素style
const onMouseMove = event => {
event.stopPropagation();
event.preventDefault();
const clientX = event.clientX;
const clientY = event.clientY;
const width = style.width + clientX - origin.current.x;
const height = style.height + clientY - origin.current.y;
setState({ width, height });
};
// 鼠标按下
const onMouseDown = event => {
event.stopPropagation();
event.preventDefault();
const clientX = event.clientX;
const clientY = event.clientY;
// origin移动起始坐标轴
origin.current = { x: clientX, y: clientY };
bindEvents();
};
// 鼠标释放后解绑事件
const onMouseUp = event => {
unbindEvents();
};
const bindEvents = () => {
document.addEventListener("mouseup", onMouseUp);
document.addEventListener("mousemove", onMouseMove);
document.addEventListener("mouseleave", onMouseUp);
};
const unbindEvents = () => {
document.removeEventListener("mouseup", onMouseUp);
document.removeEventListener("mousemove", onMouseMove);
document.removeEventListener("mouseleave", onMouseUp);
};
React.useEffect(() => {
return () => {
unbindEvents();
};
}, []);
return (
<div style={{ border: "1px solid green" }}>
我是绿色的盒子的盒子
<div
onMouseDown={onMouseDown}
style={{ border: "1px solid red", ...style }}
>
<h3>我是红色的盒子,点我拖动改变大小</h3>
</div>
</div>
);
};
复制代码
const [pointList] = React.useState([
"lt",
"rt",
"lb",
"rb",
"l",
"r",
"t",
"b"
]);
复制代码
<div>
<div>我是要改变大小的元素A</div>
<div>
经过拖动我能够改变元素A的大小
<Point>
</div>
<div>
复制代码
代码较多 能够直接fork个人仓库 连接在文章开头 下文为主要代码
或者在线演示 codesandbox.io/s/zen-bogda…git
const onMouseMove = moveEvent => {
const point = ref.current.pointId;
let downEvent = moveEvent;
downEvent.stopPropagation();
downEvent.preventDefault();
const activeNode = document.getElementById("box");
const activeStyle = props.style;
if (!activeNode) {
return;
}
const { pos, startX, startY } = ref.current;
const nextPos = { ...pos };
ref.current.hasMoved = true;
let height = Number(nextPos.height);
let width = Number(nextPos.width);
let top = Number(nextPos.top) || 0;
let left = Number(nextPos.left) || 0;
let currX = moveEvent.clientX;
let currY = moveEvent.clientY;
let disY = currY - startY;
let disX = currX - startX;
let hasT = /t/.test(point);
let hasB = /b/.test(point);
let hasL = /l/.test(point);
let hasR = /r/.test(point);
let newHeight = +height + (hasT ? -disY : hasB ? disY : 0);
let newWidth = +width + (hasL ? -disX : hasR ? disX : 0);
nextPos.height = newHeight > 0 ? newHeight : 0;
nextPos.width = newWidth > 0 ? newWidth : 0;
nextPos.left = +left + (hasL ? disX : 0);
nextPos.top = +top + (hasT ? disY : 0);
// 根据拖动方向算出最终拖动结果style 并在拖动过程当中保持cursor 不变
// 画布和被拖动元素的cursor 在拖动时候与Point保持一致
const style = {
...activeStyle,
left: `${nextPos.left}px`,
top: `${nextPos.top}px`,
width: `${nextPos.width}px`,
height: `${nextPos.height}px`,
cursor: directionKey[point]
};
const paiting = document.getElementById("painting-main");
if (paiting) {
paiting.style.cursor = directionKey[point];
}
stateRef.current = style;
props.handleStyle(stateRef.current);
};
const onMouseUp = event => {
// 记录这次操做结果
if (ref.current.hasMoved) {
}
// 还原全部数据
const paiting = document.getElementById("painting-main");
if (paiting) {
paiting.style.cursor = "default";
}
stateRef.current = _.omit(stateRef.current, ["cursor"]);
props.handleStyle(stateRef.current);
stateRef.current = {};
ref.current = {};
// 解除绑定
unbindEvents();
};
复制代码