• react可视化编辑器 第一章 拖拽


    效果:
    在这里插入图片描述
    实现可视化编辑器,第一步难点 是 拖拽

    提示:链接和图片默认是可拖动的,不需要draggable属性。

    在拖放操作的不同阶段使用并可能发生许多事件属性:

    • 在可拖动目标上触发的事件(源元素):
      ondragstart - 当用户开始拖动元素时触发
      ondrag - 拖动元素时触发
      ondragend - 在用户完成拖动元素时触发

    • 在放置目标上触发的事件:
      ondragenter - 当被拖动的元素进入放置目标时触发
      ondragover - 当被拖动的元素超过放置目标时触发
      ondragleave - 当被拖动的元素离开放置目标时触发
      ondrop - 当被拖动的元素放在放置目标上时触发

    在这里插入图片描述

    这种代码结构更加清楚, demo 和content是俩个完全没有关系的兄弟div

    现在需求的 红色拖拽到蓝色中, 这里的方法是定位

    情况一:

    • demo的操作逻辑代码
          
    handleDragStart(e, 1)} style={{ width: '100px', height: '100px', backgroundColor: 'red', margin: '30px', }} > demo2
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
      const handleDragStart = (e: DragEvent, id: number) => {
        e.dataTransfer.setData('text/plain', id.toString());  // 存储id, 和 data-XX一个道理
      };
    
    • 1
    • 2
    • 3
    • content 的逻辑代码
       
    { width: '300px', height: '300px', margin: '30px', backgroundColor: 'blue', position: 'relative', }} > content {demos.map((demo) => (
    { width: '100px', height: '100px', backgroundColor: 'red', position: 'absolute', left: `${demo.x}px`, top: `${demo.y}px`, }} > demo {demo.id}
    ))}
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
      const handleDrop = (e: DragEvent) => {
        e.preventDefault();
        const clientX = e.clientX;
        const clientY = e.clientY;
        const contentStyle = document
          .getElementById('content')
          .getBoundingClientRect();
    
        const x = clientX - contentStyle.left
        const y = clientY - contentStyle.top;
        const newDemo: Demo = { x, y, id: +new Date() };
        setDemos([...demos, newDemo]);
      };
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    上面代码测试结果:
    在这里插入图片描述

    代码测试 ,会有一些偏差,原因是 鼠标拖拽的位置的不是红色div的左上角顶点, 这样的就不会发生偏移, 但是实际情况无法保证每次都是拖拽顶点, 那需要在开始拖拽的计算的鼠标相对于红色div的偏移值

    情况二:完整的代码

    import React, { useState, DragEvent, useEffect, MouseEvent } from 'react';
    
    interface Demo {
      id: number;
      x: number;
      y: number;
    }
    
    const App: React.FC = () => {
      const [demos, setDemos] = useState([]);
    
      const handleDragStart = (e: DragEvent, id: number) => {
        e.dataTransfer.setData('text/plain', id.toString());
    
        const offsetX = e.clientX - e.currentTarget.getBoundingClientRect().left;
        const offsetY = e.clientY - e.currentTarget.getBoundingClientRect().top;
        e.dataTransfer.setData('offsetX', offsetX.toString());
        e.dataTransfer.setData('offsetY', offsetY.toString());
      };
    
      const handleDrop = (e: DragEvent) => {
        e.preventDefault();
        const clientX = e.clientX;
        const clientY = e.clientY;
        const contentStyle = document
          .getElementById('content')
          .getBoundingClientRect();
        const offsetX = e.dataTransfer.getData('offsetX');
        const offsetY = e.dataTransfer.getData('offsetY');
        const x = clientX - contentStyle.left - offsetX;
        const y = clientY - contentStyle.top - offsetY;
        const newDemo: Demo = { x, y, id: +new Date() };
        setDemos([...demos, newDemo]);
      };
    
      const handleDragOver = (e: DragEvent) => {
        e.preventDefault();
      };
    
      const onMouseDown = (e: MouseEvent) => {
        console.info('onMouseDown', e);
      };
    
      const onMouseUp = (e: MouseEvent) => {
        console.info('onMouseUp', e);
      };
    
      const onDragEnd = (e: MouseEvent) => {
        console.info('onDragEnd', e);
      };
    
      return (
        
    handleDragStart(e, 1)} onDragEnd={onDragEnd} style={{ width: '100px', height: '100px', backgroundColor: 'red', margin: '30px', }} > demo2
    { width: '300px', height: '300px', margin: '30px', backgroundColor: 'blue', position: 'relative', }} > content {demos.map((demo) => (
    { width: '100px', height: '100px', backgroundColor: 'red', position: 'absolute', left: `${demo.x}px`, top: `${demo.y}px`, }} > demo {demo.id}
    ))}
    ); }; export default App;
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
  • 相关阅读:
    5.基于飞蛾扑火算法(MFO)优化的VMD参数(MFO-VMD)
    两个浏览器页面数据通信,页面是非父子、非兄弟关系
    易货:一种古老而有效的商业模式
    Linux项目车牌识别-imx6ull芯片
    Qt使用I.MX6U开发板上的按键(原理:将电脑键盘方向键↓在Qt中的枚举值与开发板中按键定义的枚举值一致,这样电脑端测试效果就与开发板的一致)
    电脑静态ip地址在哪里找
    MinIO实战
    显示图像2
    PTE-RA总结
    Metabase学习教程:视图-7
  • 原文地址:https://blog.csdn.net/Zhooson/article/details/136768616