可視化搭建的項目要求元素能夠像作圖軟件同樣隨意的拖動改變大小 那怎麼實現這個功能呢?先來一個簡單的版本吧?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();
};
複製代碼