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

从零实现一套低代码(保姆级教程) --- 【3】实现Button组件和画布区的拖拽

摘要

目前是每天更新一篇, 因为我不止要写文章,这些代码也是我正在敲的。可能速度没有那么快,但是这个频率感觉还是可以的。

本篇是这个系列的第三篇,如果你是第一次看到这个文章,那你应该会对低代码有那么一丢丢兴趣或者很有兴趣。从标题来看,也知道我这个系列就是实现一个低代码的项目。

那如果你想知道,我实现的项目的样子是什么样的,可以访问下面的链接:
↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓
XinBuilder 点击跳转

如果你有兴趣,跟着实现这么一套代码,那么你可以从第一章节开始阅读:
从零实现一套低代码(保姆级教程) — 【1】初始化项目,实现左侧组件列表

因为上一篇文章,没有额外的提交,所有的代码都写在了文章里,所以这里就直接继续上一篇开始说。

在上一篇结束后,我们实现了左侧组件拖拽到画布区的效果!!!

但是因为我们组件里面只有一个文本,所以今天我们主要来实现组件,以及画布区中组件的拖拽。
在这里插入图片描述

1.组件的实现

在上一节中,我们在Button组件中,从props里面接收了style,从而实现组件在画布区的定位效果。

但是之所以显示文本,是因为我们写的就是文本,现在我们给它改成antD里面的Button组件。

import { Button as AntButton } from 'antd'export default function Button(props: any) {const {style} = propsreturn (<div style={style}><AntButton>按钮</AntButton></div>)
}

这里注意一下,因为我的组件就叫Button,如果引入antD的Button时,没有改名会引起报错

你可以有两种解决办法,一种是像我这样,另一种就是修改自己这个组件的名,例如不叫Button,叫XButton即可

当你修改完后,再拖拽组件,那么在画布区显示的就不是一段文本了!!!!

在这里插入图片描述

2.实现画布区的拖拽

现在呢,我们拖拽到画布区的组件,就定死在那里了,不能拖拽,现在我们要给画布区的组件添加拖拽的效果。

现在请读者打开mainPart下的index.jsx文件,看一下最终的return。

我们在遍历comList的时候,返回的Com外层应该包一层div用来实现拖拽的效果。
在这里插入图片描述

同时也要给这个外层的div一个拖拽的方法,onDragStart,由于在画布区拖拽组件,也只能拖拽到画布区,所以我们不需要像上次一样,做一些禁止默认行为的处理了。

  // 画布区的组件拖拽方法const onDragStart = (com: ComJson) => {return () => {}}return (<div onDrop={onDrop} onDragOver={onDragOver} onDragEnter={onDragEnter} className='mainCom'>{comList.map(com => {const Com = components[com.comType as keyof typeof components];// 在外面包一层控制拖拽的divreturn <div draggable onDragStart={onDragStart(com)}><Com style={com.style} /></div>})}</div>)

OK。现在请打开浏览器看一下实现的效果吧,是不是发现有点问题,每次你在画布区拖拽后,都会生成一个新的组件,而不是组件的移动。这是为什么呢?

在这里插入图片描述
答案在我们写的onDrop方法里,因为每次拖拽完都会触发onDrop方法,每次都会push一个新的组件

所以我们应该是从左侧组件列表拖拽的时候,进行push。如果是在画布区拖拽,我们只需要更新style属性即可。

那怎么判断是画布区拖拽的组件还是左侧栏拖拽的组件呢?我们可以在这里的onDragStart里,将window.nowCom设定为一个特殊的值。在onDrop根据这个值去判断走哪条分支。

  // 用于保存当前画布区拖拽的节点const [dragCom, setDragCom] = useState<ComJson | null>(null)const onDrop = (e: any) => {const endLeft = e.clientX;const endTop = e.clientY;const style = {position: 'absolute',left: endLeft + 'px',top: endTop + 'px',zIndex:100}// 判断当前拖拽的节点是从画布区拖拽,还是左侧组件栏拖拽if(window.nowCom === 'renderCom' && dragCom) {dragCom.style = style}else{comList.push({comType: window.nowCom,style})}setComList([...comList])}const onDragStart = (com: ComJson) => {return () => {// 设置拖拽的节点和nowCom的固定值window.nowCom = 'renderCom';setDragCom(com)}}

现在请再看一下效果,在画布区的拖拽就已经解决了。
但是呢,是不是位置不太准确呢

3.计算组件拖拽后的位置

好像在画布区拖拽完组件,新的位置总是差了那么一点,这是为什么呢?
先给一点提示,如果你拖拽的时候,鼠标位置在组件的左上角,那就没有问题了。

答案是,你给组件的left和top的定位,是基于鼠标位置的,也就是说,你把鼠标距离顶部和左部的距离,给了组件,那如果组件有自己的宽高,那么这个定位就是不准的。

所以为了算出正确的位置,我们应该计算出鼠标向左移动的距离和向上移动的距离。
然后加上组件本身的left和top值。

组件位置.left = 组件旧位置.left + 鼠标向左移动的距离
组件位置.top= 组件旧位置.top+ 鼠标向上移动的距离

那怎么计算鼠标移动的距离呢?我们可以在dragStart中,保存鼠标的位置。drop事件里,再保存一下鼠标的位置,诶?两者的差值不就是鼠标移动的位置嘛?
简单画一下流程图:

在这里插入图片描述

  // 用来保存鼠标的开始位置和结束位置const distance = useRef<Distance>({startLeft: void 0,startTop: void 0,endLeft: void 0,endTop: void 0})const onDragStart = (com: ComJson) => {return (e: any) => {window.nowCom = 'renderCom';setDragCom(com);// 开始位置distance.current.startLeft = e.clientX;distance.current.startTop = e.clientY;}}const onDrop = (e: any) => {// 鼠标的结束位置distance.current.endLeft = e.clientX;distance.current.endTop = e.clientY;let style: any;if(window.nowCom === 'renderCom' && dragCom && dragCom.style) {// 根据鼠标位置的差值计算组件位置dragCom.style = {...dragCom.style,left: parseInt(dragCom.style.left) + (e.clientX - (distance.current.startLeft || 0)) + 'px',top: parseInt(dragCom.style.top) + (e.clientY - (distance.current.startTop || 0)) + 'px'}}else{style = {position: 'absolute',left: distance.current.endLeft + 'px',top: distance.current.endTop + 'px',zIndex:100}comList.push({comType: window.nowCom,style})}setComList([...comList])}

基于上面的实现,我们就完成了组件在画布区的拖拽了。

本章内容会提交在github上:
https://github.com/TeacherXin/XinBuilder2
commit: 第三节:实现Button组件和画布区的拖拽

博主补充

那如果现在你已经完成了所有的过程,你可以自己把其他组件的代码也补充一下。
我会在github上提交一段代码,用来补充文本框组件的代码,内容可以在github上查看

https://github.com/TeacherXin/XinBuilder2
commit: 第三节:实现Input组件代码

第二个问题,为什么鼠标的位置我们通过useRef来进行存储。因为这四个变量不需要更新去渲染组件,所以没必要通过useState去管理。但是呢,每次更新组件的时候还需要拿到之前的值,所以我们使用useRef进行管理。

第三个问题,现在我们有comList保存所有的组件数据,dragCom保存在画布区拖拽的组件。这个在后面,我们会采用redux进行管理,会有所更改,目前的话我们先使用这种模式来把整个流程串通。

最后,博主的TS可能没有那么熟练,如果有建议的话,博主也会积极采纳的!!!!

相关文章:

从零实现一套低代码(保姆级教程) --- 【3】实现Button组件和画布区的拖拽

摘要 目前是每天更新一篇&#xff0c; 因为我不止要写文章&#xff0c;这些代码也是我正在敲的。可能速度没有那么快&#xff0c;但是这个频率感觉还是可以的。 本篇是这个系列的第三篇&#xff0c;如果你是第一次看到这个文章&#xff0c;那你应该会对低代码有那么一丢丢兴趣…...

仓储1、10、11代电子标签接口文档

标签注册 仓储1代注册 侧面按钮连按三次&#xff0c; 注册成功&#xff1a;红灯变绿灯 仓储10代注册 右下角左下角组合按键触发注册 注册成功&#xff1a;右上角绿灯变红灯 仓储11代注册 磁体靠近条码附近&#xff0c;触发标签注册到系统 注册成功&#xff1a;闪红灯边绿…...

iOS将framework转为xcframework

拆分framework 先把framework拷贝到两个文件夹下边&#xff0c;这里只需要armv7、arm64、x86_64。 mkdir iphoneos iphonesimulator cp -R mysdk.framework iphoneos cp -R mysdk.framework iphonesimulator 把iphoneos中的模拟器指令集删除&#xff0c;只保留armv7和arm64 …...

2018年第七届数学建模国际赛小美赛C题共享单车对城市交通的影响解题全过程文档及程序

2018年第七届数学建模国际赛小美赛 C题 共享单车对城市交通的影响 原题再现&#xff1a; 共享自行车改变了许多城市的交通状况&#xff0c;许多大城市引入共享自行车来解决交通问题。我们需要定量评估共享自行车对城市交通的影响&#xff0c;以及相关的经济、社会和环境影响。…...

【数据结构】线段树算法总结(单点修改)

知识概览 用作单点修改的线段树有4个操作&#xff1a; pushup&#xff1a;由子节点的信息计算父节点的信息build&#xff1a;初始化一棵树modify&#xff1a;修改一个区间query&#xff1a;查询一个区间 线段树用一维数组来存储&#xff1a; 编号是x的节点&#xff0c;它的父节…...

数据分析:小红书过节“仪式感”营销种草

导语 过年的氛围是越来越浓&#xff0c;走亲访友&#xff0c;过节送礼都准备起来&#xff01;据千瓜数据显示&#xff0c;“轻松买到仪式感”热度攀升&#xff0c;作为站内扶持的新兴话题&#xff0c;11月上线以来浏览量超2.5亿&#xff0c;笔记数超过20万篇。 看来&#xff…...

Zookeeper-应用实战

Zookeeper Java客户端实战 ZooKeeper应用的开发主要通过Java客户端API去连接和操作ZooKeeper集群。 ZooKeeper官方的Java客户端API。 第三方的Java客户端API&#xff0c;比如Curator。 ZooKeeper官方的客户端API提供了基本的操作:创建会话、创建节点、读取节点、更新数据、…...

2017年第六届数学建模国际赛小美赛A题飓风与全球变暖解题全过程文档及程序

2017年第六届数学建模国际赛小美赛 A题 飓风与全球变暖 原题再现&#xff1a; 飓风&#xff08;也包括在西北太平洋被称为“台风”的风暴以及在印度洋和西南太平洋被称为“严重热带气旋”&#xff09;具有极大的破坏性&#xff0c;往往造成数百人甚至数千人死亡。   许多气…...

Node.js使用Express框架写服务端接口时,如何将接口拆分到不同文件中

项目目录结构说明&#xff1a; node.js连接mysql数据库步骤可参考&#xff1a;Node.js 连接 MySQL | 菜鸟教程 1、拆分之前的写法&#xff0c;未区分模块&#xff0c;所有接口api都写在了入口文件app.js中&#xff1b; 需求&#xff1a;想要将接口api拆分成根据不同的业务模块…...

Unity | Shader基础知识(第八集:案例<漫反射材质球>)

目录 一、本节介绍 1 上集回顾 2 本节介绍 二、什么是漫反射材质球 三、 漫反射进化史 1 三种算法结果的区别 2 具体算法 2.1 兰伯特逐顶点算法 a.本小节使用的unity自带结构体。 b.兰伯特逐顶点算法公式 c.代码实现——兰伯特逐顶点算法 2.2 代码实现——兰伯特逐…...

NCV8460ADR2G在汽车和工业应用中高压侧驱动如何破?

NCV8460ADR2G是一款完全保护的高压侧驱动器&#xff0c;可用于开关各种负载&#xff0c;如灯泡、电磁阀和其他致动器。该器件可以通过有源电流限制和高温关断针对过载情况进行内部保护。 诊断状态输出引脚提供了高温以及开关状态开路负载情况的数字故障指示。 特性&#xff1a;…...

在打日志时,如何使用snowflake-id快速方便得随机获取query的唯一id

步骤一&#xff1a;安装snowflake-id pip install snowflake-id步骤二&#xff1a;代码示例 from snowflake import SnowflakeGeneratorgen SnowflakeGenerator(42)for i in range(100):val next(gen)print(val)参考文档&#xff1a; https://pypi.org/project/snowflake-…...

Linux之yum管理器

目录 yum管理器 yum相关指令 yum list yum list | grep yum install yum remove 拓展 1.yum install -y man-pages 2.切换yum源 3.yum install -y epel-release 4. yum install -y lrzsz rz指令 sz指令 在window系统上&#xff0c;我们会在电脑自带的应用商…...

ubuntu 搭建本地私有pip源

# 搭建本地私有pip源 pip install pip2pi# 创建目录 mkdir /data/work/PyPip/ mkdir /data/work/PyPip/packages cd /data/work/PyPip/# 创建需要从外网源同步的package touch requirements_roop.txt# 批量同步 pip2tgz /data/work/PyPip/packages -r requirements_roop.txt# 同…...

声音克隆:让你的声音变得无所不能

什么是声音克隆&#xff1f; 声音克隆是一种利用人工智能技术&#xff0c;根据一段声音样本&#xff0c;生成与之相似或完全相同的声音的过程。声音克隆可以用于多种场景。 声音克隆的原理是利用深度学习模型&#xff0c;从声音样本中提取声音特征&#xff0c;然后根据目标文…...

hadoop02_HDFS的API操作

HDFS的API操作 1 HDFS 核心类简介 Configuration类&#xff1a;处理HDFS配置的核心类。 FileSystem类&#xff1a;处理HDFS文件相关操作的核心类,包括对文件夹或文件的创建&#xff0c;删除&#xff0c;查看状态&#xff0c;复制&#xff0c;从本地挪动到HDFS文件系统中等。…...

使用C语言将ASCII明文编码为GSM短信体格式

一、背景介绍 GSM&#xff08;Global System for Mobile Communications&#xff09;是全球移动通信系统的简称&#xff0c;而GSM 03.38是GSM系统中用于短信编码的标准。GSM 03.38字符集采用7-bit编码&#xff0c;与ASCII的8-bit编码有所不同。为了将ASCII编码的文本转换为GSM…...

docker搭建mysql8.0.32,实现主从复制(一主两从)

安装docker的步骤、使用命令就不写了&#xff0c;本文章是基于会使用docker、linux基本命令的基础上来写的。 开始步骤&#xff1a; 1. 拉取 mysql 镜像 docker pull mysql:8.0.32 2. 启动容器并运行mysql a. 准备mysql的配置文件&#xff08;该配置文件是&#xff1a;mysq…...

AOP springboot

1. 2. Around(“execution(* com.example.demo.controller..(…))”) 代表所有的类下面所有的方法任意参数 3....

Python Flask 基础入门第六课: Flask 全局变量 current_app, g 以及 session各自如何使用 有什么差异

全局变量 current_app, g 以及 session 全局变量差异汇总表current_app章节1 current_app - 当前应用实例current_app的基本概念current_app的作用current_app的使用 章节2&#xff1a;current_app的上下文什么是应用上下文&#xff1f;current_app与应用上下文的关系current_a…...

高性能零依赖Vue3跑马灯组件:企业级动态内容展示解决方案

高性能零依赖Vue3跑马灯组件&#xff1a;企业级动态内容展示解决方案 【免费下载链接】vue3-marquee A simple marquee component with ZERO dependencies for Vue 3. 项目地址: https://gitcode.com/gh_mirrors/vu/vue3-marquee Vue3-Marquee是一个专为Vue 3设计的零依…...

本地部署开源大模型聊天界面Serge:零成本私有化AI助手实战指南

1. 项目概述&#xff1a;一个能在本地运行的开源大语言模型聊天界面如果你和我一样&#xff0c;对大型语言模型&#xff08;LLM&#xff09;充满好奇&#xff0c;既想体验它们强大的对话和推理能力&#xff0c;又对数据隐私、网络依赖和API调用成本心存顾虑&#xff0c;那么ser…...

在线教程丨单卡即可爆改,面壁智能等开源MiniCPM-V-4.6,1.3B端侧模型支持图像理解/视频理解/OCR/多轮多模态对话

过去几年&#xff0c;整个 AI 行业几乎都笼罩在 Scaling Law 的叙事之下。参数越大、训练数据越多&#xff0c;模型似乎就越接近「通用智能」。从千亿到万亿参数&#xff0c;大模型不断刷新人们对推理能力与世界知识的想象&#xff0c;也让「堆算力、卷规模」成为行业默认的发展…...

突破性AI编程工具破解方案:cursor-free-vip技术深度解析与全栈实施指南

突破性AI编程工具破解方案&#xff1a;cursor-free-vip技术深度解析与全栈实施指南 【免费下载链接】cursor-free-vip [Support 0.45]&#xff08;Multi Language 多语言&#xff09;自动注册 Cursor Ai &#xff0c;自动重置机器ID &#xff0c; 免费升级使用Pro 功能: Youve …...

边缘计算安全:保护边缘环境的安全

边缘计算安全&#xff1a;保护边缘环境的安全 一、边缘计算安全概述 1.1 边缘计算安全的定义 边缘计算安全是指保护边缘计算环境中的数据、设备和应用的安全。它包括边缘节点的安全、网络安全、数据安全和应用安全等方面。 1.2 边缘计算安全的价值 数据保护&#xff1a;保护边缘…...

Windows安卓应用安装器:终极免费方案,3分钟搞定电脑运行安卓应用!

Windows安卓应用安装器&#xff1a;终极免费方案&#xff0c;3分钟搞定电脑运行安卓应用&#xff01; 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 你是否曾经遇到过…...

从‘一片蓝’到‘五彩斑斓’:手把手教你美化Matlab三维柱状图,让论文图表脱颖而出

从‘一片蓝’到‘五彩斑斓’&#xff1a;科研级Matlab三维柱状图视觉优化全攻略 当审稿人翻开一篇论文时&#xff0c;图表往往是他们最先注意到的元素。我曾参与过多次学术期刊的评审工作&#xff0c;那些配色考究、细节精致的图表总能在第一时间抓住眼球——这不仅仅是审美问题…...

ios蓝牙开发

一、蓝牙基本概念蓝牙&#xff1a;BLE (Bluetooth Low Energy/低功耗蓝牙)&#xff0c;一般应用苹果的官方框架基于 <CoreBluetooth/CoreBluetooth.h> 框架进行开发。中心设备&#xff1a;用于扫描周边蓝牙外设的设备&#xff0c;比如我们上面所说的中心者模式&#xff0…...

告别枯燥理论:用51单片机和DAC0832做个迷你音乐合成器,汇编语言实现《小星星》

用51单片机和DAC0832打造迷你音乐合成器&#xff1a;汇编语言实现《小星星》全解析 在嵌入式系统学习的道路上&#xff0c;很多初学者都会遇到一个共同的问题&#xff1a;如何将枯燥的理论知识转化为有趣的实际应用&#xff1f;今天&#xff0c;我们就来打破常规&#xff0c;用…...

先进制程EPE挑战:从系统误差到量测革命,如何驯服边缘位置误差

1. 从“理所当然”到“如履薄冰”&#xff1a;边缘位置误差如何成为先进制程的“隐形杀手”在半导体行业过去的黄金岁月里&#xff0c;工程师们有一个近乎奢侈的“共识”&#xff1a;芯片内部那些由光刻、刻蚀定义的特征边缘&#xff0c;可以被理所当然地看作是笔直且在不同工艺…...