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

  • 6
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值