上海 房地产网站建设,网站被k是什么意思,信誉好的手机网站建设,杭州 高端网站定制摘要
目前是每天更新一篇#xff0c; 因为我不止要写文章#xff0c;这些代码也是我正在敲的。可能速度没有那么快#xff0c;但是这个频率感觉还是可以的。
本篇是这个系列的第三篇#xff0c;如果你是第一次看到这个文章#xff0c;那你应该会对低代码有那么一丢丢兴趣…摘要
目前是每天更新一篇 因为我不止要写文章这些代码也是我正在敲的。可能速度没有那么快但是这个频率感觉还是可以的。
本篇是这个系列的第三篇如果你是第一次看到这个文章那你应该会对低代码有那么一丢丢兴趣或者很有兴趣。从标题来看也知道我这个系列就是实现一个低代码的项目。
那如果你想知道我实现的项目的样子是什么样的可以访问下面的链接 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ XinBuilder 点击跳转
如果你有兴趣跟着实现这么一套代码那么你可以从第一章节开始阅读 从零实现一套低代码保姆级教程 — 【1】初始化项目实现左侧组件列表
因为上一篇文章没有额外的提交所有的代码都写在了文章里所以这里就直接继续上一篇开始说。
在上一篇结束后我们实现了左侧组件拖拽到画布区的效果 但是因为我们组件里面只有一个文本所以今天我们主要来实现组件以及画布区中组件的拖拽。
1.组件的实现
在上一节中我们在Button组件中从props里面接收了style从而实现组件在画布区的定位效果。
但是之所以显示文本是因为我们写的就是文本现在我们给它改成antD里面的Button组件。
import { Button as AntButton } from antdexport 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} classNamemainCom{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] useStateComJson | 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 useRefDistance({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可能没有那么熟练如果有建议的话博主也会积极采纳的