当前位置: 首页 > news >正文

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

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

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

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

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

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

在这里插入图片描述

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

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

情况一:

  • demo的操作逻辑代码
      <divid="demo"draggableonDragStart={(e) => handleDragStart(e, 1)}style={{width: '100px',height: '100px',backgroundColor: 'red',margin: '30px',}}>demo2</div>
  const handleDragStart = (e: DragEvent<HTMLDivElement>, id: number) => {e.dataTransfer.setData('text/plain', id.toString());  // 存储id, 和 data-XX一个道理};
  • content 的逻辑代码
   <divid="content"onDrop={handleDrop}style={{width: '300px',height: '300px',margin: '30px',backgroundColor: 'blue',position: 'relative',}}>content{demos.map((demo) => (<divkey={demo.id}style={{width: '100px',height: '100px',backgroundColor: 'red',position: 'absolute',left: `${demo.x}px`,top: `${demo.y}px`,}}>demo {demo.id}</div>))}</div>
  const handleDrop = (e: DragEvent<HTMLDivElement>) => {e.preventDefault();const clientX = e.clientX;const clientY = e.clientY;const contentStyle = document.getElementById('content').getBoundingClientRect();const x = clientX - contentStyle.leftconst y = clientY - contentStyle.top;const newDemo: Demo = { x, y, id: +new Date() };setDemos([...demos, newDemo]);};

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

代码测试 ,会有一些偏差,原因是 鼠标拖拽的位置的不是红色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<Demo[]>([]);const handleDragStart = (e: DragEvent<HTMLDivElement>, 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<HTMLDivElement>) => {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<HTMLDivElement>) => {e.preventDefault();};const onMouseDown = (e: MouseEvent<HTMLDivElement>) => {console.info('onMouseDown', e);};const onMouseUp = (e: MouseEvent<HTMLDivElement>) => {console.info('onMouseUp', e);};const onDragEnd = (e: MouseEvent<HTMLDivElement>) => {console.info('onDragEnd', e);};return (<div><divid="demo"draggableonDragStart={(e) => handleDragStart(e, 1)}onDragEnd={onDragEnd}style={{width: '100px',height: '100px',backgroundColor: 'red',margin: '30px',}}>demo2</div><divid="content"onDrop={handleDrop}onDragOver={handleDragOver}onMouseDown={onMouseDown}onMouseUp={onMouseUp}style={{width: '300px',height: '300px',margin: '30px',backgroundColor: 'blue',position: 'relative',}}>content{demos.map((demo) => (<divkey={demo.id}style={{width: '100px',height: '100px',backgroundColor: 'red',position: 'absolute',left: `${demo.x}px`,top: `${demo.y}px`,}}>demo {demo.id}</div>))}</div></div>);
};export default App;

相关文章:

  • C语言如何进⾏字符数组的连接?
  • 2023年中国抗DDoS市场规模现状及竞争格局,公有云抗DDoS是主要增长点
  • 数学建模--MATLAB基本使用
  • Day39:安全开发-JavaEE应用SpringBoot框架Actuator监控泄漏Swagger自动化
  • 科研绘图一:箱线图(添加贝赛尔曲线)
  • 获取扇区航班数
  • Linux-网络基础
  • 【解惑】离线版本的软件如何实现“授权验证”和“使用有效期”验证的
  • iPhone 的健康数据采用的是 FHIR 传输格式
  • RK3568平台开发系列讲解(基础篇)内核是如何发送事件到用户空间
  • 计算机网络----计算机网络的基础
  • vue防止用户连续点击造成多次提交
  • ISIS接口认证实验简述
  • git:码云仓库提交以及Spring项目创建
  • 教程:如何制作和分享自定义GPT
  • ES6指北【2】—— 箭头函数
  • [分享]iOS开发 - 实现UITableView Plain SectionView和table不停留一起滑动
  • 【译】理解JavaScript:new 关键字
  • CNN 在图像分割中的简史:从 R-CNN 到 Mask R-CNN
  • ECMAScript入门(七)--Module语法
  • iOS | NSProxy
  • JavaScript 是如何工作的:WebRTC 和对等网络的机制!
  • jquery ajax学习笔记
  • OSS Web直传 (文件图片)
  • Python连接Oracle
  • Python学习之路16-使用API
  • scrapy学习之路4(itemloder的使用)
  • Vue2.x学习三:事件处理生命周期钩子
  • WordPress 获取当前文章下的所有附件/获取指定ID文章的附件(图片、文件、视频)...
  • 百度贴吧爬虫node+vue baidu_tieba_crawler
  • 深度解析利用ES6进行Promise封装总结
  • 算法-图和图算法
  • 网络应用优化——时延与带宽
  • 一道面试题引发的“血案”
  • 【云吞铺子】性能抖动剖析(二)
  • 带你开发类似Pokemon Go的AR游戏
  • ​configparser --- 配置文件解析器​
  • !$boo在php中什么意思,php前戏
  • #Linux(权限管理)
  • #Spring-boot高级
  • (Matalb分类预测)GA-BP遗传算法优化BP神经网络的多维分类预测
  • (翻译)Entity Framework技巧系列之七 - Tip 26 – 28
  • (含react-draggable库以及相关BUG如何解决)固定在左上方某盒子内(如按钮)添加可拖动功能,使用react hook语法实现
  • (十七)Flask之大型项目目录结构示例【二扣蓝图】
  • (使用vite搭建vue3项目(vite + vue3 + vue router + pinia + element plus))
  • (一)C语言之入门:使用Visual Studio Community 2022运行hello world
  • (转)h264中avc和flv数据的解析
  • (转)PlayerPrefs在Windows下存到哪里去了?
  • **CI中自动类加载的用法总结
  • .NET BackgroundWorker
  • .NET Core WebAPI中封装Swagger配置
  • .net websocket 获取http登录的用户_如何解密浏览器的登录密码?获取浏览器内用户信息?...
  • .net/c# memcached 获取所有缓存键(keys)
  • .net使用excel的cells对象没有value方法——学习.net的Excel工作表问题
  • /proc/vmstat 详解