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<HTMLDivElement>) => {
    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 (
    <div className={styles['resize-content']}>
      <div className={styles['resize-item']} onMouseDown={onMouseDown}>
        {points.map((item, index) => (
          <div
            key={index}
            data-key={item}
            className={[
              styles['resize-control-btn'],
              styles[`resize-control-${item}`],
            ].join(' ')}
          ></div>
        ))}
      </div>
    </div>
  );
};

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;
}

最近更新

  1. TCP协议是安全的吗?

    2024-03-18 07:04:03       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-18 07:04:03       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-18 07:04:03       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-18 07:04:03       18 阅读

热门阅读

  1. 使用TensorFlow 2.4进行深度学习

    2024-03-18 07:04:03       19 阅读
  2. 【C++】每日一题 219 存在重复元素

    2024-03-18 07:04:03       20 阅读
  3. 利用卷积神经网络进行人脸识别

    2024-03-18 07:04:03       22 阅读
  4. microk8s使用本地库的镜像部署服务

    2024-03-18 07:04:03       19 阅读
  5. Mapper.xml映射文件

    2024-03-18 07:04:03       17 阅读
  6. 蓝桥杯day3刷题日记--P9240 冶炼金属

    2024-03-18 07:04:03       16 阅读
  7. python request pandas excel 接口自动化测试框架

    2024-03-18 07:04:03       17 阅读
  8. 【XML】xml转Freemind思维导图

    2024-03-18 07:04:03       18 阅读