这是我参与【第四届青训营】笔记创作活动的第3天
低代码平台中的拖拽功能
低代码平台为开发者提供了便利的简单页面搭建功能,开发者只需拖拽需要的组件,手动完成布局,即可完成页面的搭建。因此拖拽功能就显得极其重要。
而我在此次项目中用到两种时机的拖拽功能
- 从左侧物料区拖到画布中的拖拽功能
- 在画布中调整组件位置的拖拽功能
从左侧物料区拖到画布中的拖拽功能
这部分主要靠h5提供的内置api--draggable属性 而要用好这个属性,首先得先知道一些概念
1,拖放事件
如果不使用drag元素的话;也可以使用onmousedown,onmouseover,onmouseup这三个来实现效果;想要拖动的话,必须在其设置draggable属性为true;需要注意的是,img和a默认为true
拖放过程中,被拖动的元素被称为目标对象,在这过程中经历的其他对象称为过程对象,最终到达的对象接叫目标对象;而每个都有其属性
源对象
ondragstart - 用户开始拖动元素时触发
ondrag - 元素正在拖动时触发
ondragend - 用户完成元素拖动后触发
过程对象
ondragenter - 当被鼠标拖动的对象进入其容器范围内时触发此事件
ondragover - 当某被拖动的对象在另一对象容器范围内拖动时触发此事件
ondragleave - 当被鼠标拖动的对象离开其容器范围内时触发此事件
目标对象
ondrop - 在一个拖动过程中,释放鼠标键时触发此事件
注意: 在拖动元素时,每隔 350 毫秒会触发 ondrag 事件。
2,dataTransfer对象
setData(name,data) 存储数据
第一个参数,要存储数据的名字(可以自己命名)
第二个参数,要存储的数据
getData(name) 获取存储名字为“name”的数据
clearData(name) 清除dataTransfer存储的数据
参数可选,为空则清空所有数据
setDragImage(element,x,y) 通过img元素设置拖放图标
element是拖拽时鼠标下面的图片(img或canvas元素)
x、y分别相对于图片的横向和纵向偏移量,对应鼠标指针
files属性
返回被拖拽的文件列表,是一个FileList对象,有length属性,可通过下标访问
项目中实现
在项目中,我给左侧物料区每个组件的盒子添加上draggable属性,每个盒子就能拖拽了,再给画布组件editor添加@drop="handleDrop"事件,而且需要给添加 @dragenter="handleDragenter"`` @dragover="handleDragover"`` @dragleave="handleDragleave"事件并为期在每个阶段执行对应应该执行的代码
handleDragenter(e) {
e.dataTransfer.dropEffect = "move";
},
handleDragover(e) {
e.preventDefault();
},
handleDragleave(e) {
e.dataTransfer.dropEffect = "none";
},
而要确定组件落入画布中的位置,可以先利用offsetY和offsetX粗略定大概位置,在之后用户稍作调整即可
handleDrop(e) {
let position = {
top: e.offsetY,
left: e.offsetX,
};
// 之后的代码。。。
},
然后通过dataTransfer对象的setData和getData来进行传值
在画布中调整组件位置的拖拽功能
首先需要将画布设为相对定位 position: relative,然后将每个组件设为绝对定位 position: absolute。除了这一点外,还要通过监听三个事件来进行移动:
mousedown事件,在组件上按下鼠标时,记录组件当前的位置,即 xy 坐标(为了方便讲解,这里使用的坐标轴,实际上 xy 对应的是 css 中的left和top。mousemove事件,每次鼠标移动时,都用当前最新的 xy 坐标减去最开始的 xy 坐标,从而计算出移动距离,再改变组件位置。mouseup事件,鼠标抬起时结束移动。
handleMousedown(e, component) {
// 获取组件起始位置
let startY = parseInt(component.style.top);
let startX = parseInt(component.style.left);
// 获取组件起始距离屏幕的位置
let { x, y } = e;
// 防抖
var timer = null;
const move = (e) => {
if (timer) return;
timer = setTimeout(() => {
// 组件当前位置 = 移动时距离屏幕的位置 - 起始距离屏幕的位置 + 组件起始位置
let style = {
top: `${e.y - y + startY}px`,
left: `${e.x - x + startX}px`,
};
component.style = formatStyle({ ...component.style, ...style });
timer = null;
}, 16);
};
// 鼠标松开移除mousemove和mouseup事件
const up = () => {
document.removeEventListener("mousemove", move);
document.removeEventListener("mouseup", up);
};
// 绑定mousemove和mouseup事件
document.addEventListener("mousemove", move);
document.addEventListener("mouseup", up);
},
此过程中,组件当前位置 = 移动时距离屏幕的位置 - 起始距离屏幕的位置 + 组件起始位置 通过此关系来确保组件能跟随鼠标移动