react可视化编辑器 第四章 顶点的缩放功能
直接上代码
import React, { useState, useEffect, useRef, useCallback } from 'react'; import styles from './index.module.scss'; const ResizableDiv = () => { // 8个点,为 left/right/top/bottom 的组合值 const points = ['lt', 'tc', 'rt', 'rc', 'br', 'bc', 'bl', 'lc']; const isDown = useRef(false); const resizeItemRef = useRef(null); const [startPos, setStartPos] = useState({ startX: 0, startY: 0, width: 0, height: 0, direction: '', }); useEffect(() => { document.addEventListener('mouseup', handleMouseUp); document.addEventListener('mousemove', handleMouseMove); return () => { document.removeEventListener('mouseup', handleMouseUp); document.removeEventListener('mousemove', handleMouseMove); }; }, [isDown, startPos]); const handleMouseUp = () => { isDown.current = false; }; const handleMouseMove = (e: { clientX: number; clientY: number }) => { if (isDown.current && resizeItemRef.current) { const { direction } = startPos; let { height, width, startX, startY } = startPos; const offsetX = e.clientX - startX; const offsetY = e.clientY - startY; switch (direction) { case 'rc': // 向右拖拽添加宽度 width += offsetX; break; case 'lc': // 增加宽度、位置同步左移 width -= offsetX; startX += offsetX; break; case 'bc': height += offsetY; break; case 'tc': height -= offsetY; startY += offsetY; break; case 'rt': height -= offsetY; startY += offsetY; width += offsetX; break; case 'lt': height -= offsetY; startY += offsetY; width -= offsetX; startX += offsetX; break; case 'br': height += offsetY; width += offsetX; break; case 'bl': height += offsetY; width -= offsetX; startX += offsetX; break; } resizeItemRef.current.style.width = width + 'px'; resizeItemRef.current.style.height = height + 'px'; } }; // 鼠标被按下 const onMouseDown = (e: React.MouseEvent) => { console.info('onMouseDown', e); if (!e.currentTarget) return; resizeItemRef.current = e.currentTarget; if (!resizeItemRef.current) return; const { offsetWidth: width, offsetHeight: height } = resizeItemRef.current; const direction = e.target.getAttribute('data-key'); console.log(direction, width, height); isDown.current = true; setStartPos({ startX: e.clientX, startY: e.clientY, width, height, direction, }); }; return ( {points.map((item, index) => ( ))} ); }; export default ResizableDiv;
.resize-content { width: 500px; height: 500px; border: 1px dashed red; margin: 30px auto; position: relative; } .resize-item { cursor: move; width: 100px; height: 100px; background-color: #ccc; position: absolute; // top: 200px; // left: 200px; } $width_height: 6px; .resize-control-btn { position: absolute; width: $width_height; height: $width_height; background: #000; user-select: none; // 注意禁止鼠标选中控制点元素,不然拖拽事件可能会因此被中断 } .resize-control-btn.resize-control-lt { cursor: nw-resize; top: 0; left: 0; } .resize-control-btn.resize-control-tc { cursor: ns-resize; top: 0; left: 50%; // transform: translateX(-50%); margin-left: $width_height / -2; } .resize-control-btn.resize-control-rt { cursor: ne-resize; top: 0; right: 0; } .resize-control-btn.resize-control-rc { cursor: ew-resize; top: 50%; margin-top: $width_height / -2; right: 0; } .resize-control-btn.resize-control-br { cursor: se-resize; bottom: 0; right: 0; } .resize-control-btn.resize-control-bc { cursor: ns-resize; bottom: 0; left: 50%; margin-left: $width_height / -2; } .resize-control-btn.resize-control-bl { cursor: sw-resize; bottom: 0; left: 0; } .resize-control-btn.resize-control-lc { cursor: ew-resize; top: 50%; margin-top: $width_height / -2; left: 0; }
文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。
还没有评论,来说两句吧...