draggable 和 sortable的JS原生实现

article/2025/8/15 0:44:00

概要

本文主要利用html 5的draggable原生特性,实现一个可拖拽的效果。我们可以创建包含多个页面节点的容器,每个容器可以包含多个节点。通过拖拽,可以移动一个容器内的节点到其他容器,每个容器内的节点和以通过拖拽改变排列顺序。

需求和设计

设计效果图如下:
在这里插入图片描述
具体需求包括:

  1. 每个容器可以包含多个节点或0个节点
  2. 每个容器内的节点可以通过拖拽转移到其他容器
  3. 每个容器内的节点可以通过拖拽改变排列顺序
  4. 容器增加或减少不影响基本的拖拽功能

代码及实现

拖拽功能的实现,主要涉及一下几个JS事件:

  1. dragstart : 当用户开始拖动目标节点时触发
  2. drop: 当被拖拽节点放入指定区域后被触发
  3. dragend: 当用户的拖拽操作完成时被触发

本文中,被拖拽节点的判定方法是采用一个工具css 类,在dragstart 中为被拖拽元素增加一个dragging的css样式类,在dragend事件中移除该类。

具体代码如下:

function dragStartHandler(e){e.target.classList.add("dragging");
}
function dragEndHandler(e){e.target.classList.remove("dragging");
}

当指定节点被拖入指定区域后,drop事件在默认情况下无法触发,需要在dragenter,drapleave和dragover中,阻止默认行为,代码如下:

function dragHandler(e){e.preventDefault();
}

基于以上处理,事件初始化代码如下,html代码请见附录:

const init = ()=> {const oLists = document.querySelector("div.lists");[...oLists.querySelectorAll("div.list")].forEach(list => {list.addEventListener("dragover", dragHandler, false);list.addEventListener("dragleave", dragHandler, false);list.addEventListener("dragenter", dragHandler, false);list.addEventListener("drop", dragDropHandler, false);let items = [...list.querySelectorAll("div.list-item")];items.forEach(item => {item.setAttribute("draggable", true);item.addEventListener("dragstart", dragStartHandler, false);item.addEventListener("dragend", dragEndHandler, false);});});
};
  1. 为每个元素容器div.list添加dragover, dragleave和dragenter事件,阻止其默认行为,保证drop事件被正常触发;
  2. 为每个可拖拽元素激活draggable属性,并绑定dragstart和dragend事件,以标识正在被拖拽的节点;
  3. drop事件处理函数是实现所有需求的关键,代码如下:
  const dragDropHandler= (e) => {const container = e.target;const classList = [...container.classList];if (!classList.includes("list")) {return;}const oDragging = document.querySelector("div.app div.dragging");const oPrev = getPrevNode(container, e.clientY);if (oPrev == null) {container.append(oDragging);} else {container.insertBefore(oDragging, oPrev);}};
  1. dragDropHandler 在释放鼠标的一刻被触发;
  2. 只有包含list css类的div才可以作为元素容器,如果不包含list类的div,将被忽略;
  3. 获取当前被拖动的节点,即div.dragging;
  4. 判断拖动节点的释放位置,如果拖动的目的位置下面没有其他可拖动元素了,则直接放到容器的最后,否则放到指定元素的上面。
  5. getPrevNode用于检测拖动元素的目的位置下面是否有其他可拖动的节点,如果有,则返回最近的节点,否则返回为空,具体代码如下:
const getPrevNode = (container, y) =>[...container.querySelectorAll("div.list-item:not(dragging)")].reduce(function (total, next) {const { height, top } = next.getBoundingClientRect();const offsetY = y - top - height / 2;if (offsetY < 0 && offsetY > total.offsetY) {return {offsetY,Element: next}}return total;}, {offsetY: Number.NEGATIVE_INFINITY}).Element;
  1. getPrevNode 接收两个参数,一个是当前鼠标拖动目的地的容器div,一个是当前鼠标y轴的位置,两个参数都可以通过drop事件的参数获取;
  2. 遍历目标容器中,确定目标位置,具体算法如下:

在这里插入图片描述
如上图所示,我们将dragging状态的节点拖入当前的容器,目标位置是item1和item2之间。现在我们通过每个元素的y轴位置,来确定谁是它的正下方节点。

  1. 设释放鼠标时候,它的y轴坐标为y;
  2. 遍历当前容器的所有节点,获取每个节点的位置(y轴坐标),即每个节点中线y轴坐标(top)和每个节点的高度(height);
  3. 比较鼠标坐标y和每个元素的y轴坐标 (top + height/2),对于item1,y - top - height/2,大于0,证明item1在dragging元素的上方,直接忽略;对于其他item,y - top - height/2和y都小于0,则说明它们都在dragging元素的下方,我们找到y - top - height/2绝对值最小的item2,该元素在dragging元素的正下方;
  4. 遍历过程中,item2和鼠标的位置最接近,证明dragging元素的下一个元素是item2,返回。

附录

html代码如下:

<div class="app"><div class="header">Draggle and Sortable</div><div class="lists"><div class="list"><div class="list-item">Item 1</div><div class="list-item">Item 2</div><div class="list-item">Item 3</div><div class="list-item">Item 4</div><div class="list-item">Item 5</div></div><div class="list"></div><div class="list"></div><div class="list"></div></div></div>

css代码如下:

* {margin : 0;padding: 0;
}div {display: flex;flex-direction: column;box-sizing: border-box;
}.app {width:100%;height: 800px;margin-top:20px;
}.header {justify-content: center;align-items: center;    font-size: 16px;font-weight: 600;line-height: 16px;
}
.lists {flex-direction: row;flex:1;height: 100%;padding : 20px;
}
.list {background: rgba(0, 0, 0, 0.1);border : 1px solid #000;flex:1;margin-left: 20px;padding-top:20px;transition: all 2s linear;
}
.list-item {justify-content: center;align-items: center;  background-color:yellow;box-shadow: 4px 4px 2px #888888;height:35px;margin:15px;}.list-item.dragging{cursor: move;opacity: 0.5;
}
.list-item:hover{cursor: move;
}

http://chatgpt.dhexx.cn/article/rMdGmNn3.shtml

相关文章

vue3使用拖拽组件draggable.next的使用教程【保姆级】

环境&#xff1a;vue3setup语法 首先放官方文档的链接&#xff1a; 中文版本&#xff1a; https://www.itxst.com/vue-draggable-next/tutorial.html &#xff08;民间翻译&#xff09; 英文版本&#xff1a;https://github.com/SortableJS/vue.draggable.next 因为自己写的过程…

vue的拖拽插件: vue.draggable

中文文档地址: vue.draggable中文文档 - itxst.comVue.Draggable是一款基于Sortable.js实现的vue拖拽插件。支持移动设备、拖拽和选择文本、智能滚动&#xff0c;可以在不同列表间拖拽、不依赖jQuery为基础、vue 2过渡动画兼容、支持撤销操作&#xff0c;总之是一款非常优秀的…

react-draggable实现拖拽详解

react-draggable 属性常用属性属性列表 事件列表举例首先安装 react-draggable实现移动 希望小编写的能够帮助到你&#x1f618; 属性 常用属性 属性默认值介绍axisxhandle拖动的方向&#xff0c;可选值 x ,y,bothhandle无指定拖动handle的classposition无handle的位置&#…

draggable拖拽组件使用

项目开发中需要用到拖拽组件&#xff0c;因为前端技术框架是vue&#xff0c;这里就使用了vue的一款拖拽插件vue.draggable&#xff0c;一般基本的需求都能满足&#xff0c;这里使用了多个draggable嵌套&#xff0c;达到两级之前相互拖拽的功能。 以下是类似teambition的效果图…

原生JS的拖拽属性draggable(详解)

摘要 作为h5新增的属性draggable&#xff0c;它能够给与一切的html元素拖动的效果。而在这个属性之下&#xff0c;也有着关于拖动效果的各个方法。 而这一篇文章&#xff0c;主要就是说一下关于draggable属性的使用以及工作场景。 1.了解draggable属性的使用 对我来讲&#…

EasyUI基础入门之Draggable(拖拽)

前面学习了easyui基础的解析器,加载器。对于他们入门阶段我们只需简单的了解下即可&#xff0c;毕竟先阶段并不会太过深入。接下来根据easyui官网文档的顺序安排学习下Draggable插件。 Draggable是什么 Draggable是easyui中用于实现拖拽功能的一个插件。利用它&#xff0c;我们…

jts-core 使用说明(二)

jts-core 使用说明 示例代码库 JTS源码底层使用说明&#xff0c;通过一下章节介绍说明 层次结构 org.locationtech.jts: algorithm - 算法包jts-io-common - I/O classes for open spatial formatsgeom - geom基础包geom.prep - 对适当准备的几何图形执行优化的几何操作类e…

java jts获取线上任意一点到起点的距离

java jts获取线上任意一点到起点的距离 近期项目要求计算某段公路上一辆车的运行轨迹&#xff0c;通过路上的设备实时获取车辆的经纬度信息并发送到后台接收。 抽象出来就是获取线上任意一点到起点的距离&#xff0c;按照一定每秒一次的频率去计算就获取该点的运动轨迹了。 主要…

JTS-Geometry 使用说明(五)

org.locationtech.jts.geom.Geometry 使用说明 示例代码库 Geometry 经纬度操作类 Geometry类继承关系 说明 平面、线性几何操作抽象类 提供的相关方法: 1.基础方法&#xff1a; 1.1 getLength:获取长度&#xff0c;线几何返回点与点之间的长度之和&#xff1b;闭合几何返回…

JAVA使用JTS 判断坐标点是否在坐标多边形内部

JAVA使用JTS 判断坐标点是否在坐标多边形内部 思路Geometry之间的关系API及参考博客代码依赖工具类测试类 思路 判断坐标点是否在坐标多边形内部&#xff0c;首先不能直接计算坐标点&#xff0c;是需要字符串坐标点转化为地理空间数据Geometry&#xff0c;然后使用JTS包中提供…

JTS学习笔记

JTS学习笔记 基础的类 Geometry geom对象Coordinate坐标类Point Point对象MultiPoint 基本对象MultiPoint等等GeometryFactory工厂对象PreparedGeometryFactoryPreparedGeometry 几何对象Geometry public abstract class Geometry implements Cloneable, Comparable, Seria…

JTS-Angle GIS几何角度计算使用说明(十八)

org.locationtech.jts.algorithm.Angle 角度计算使用说明 示例代码库 Angle 角度计算 1.Angle.angle(p0,p1) public static double angle(Coordinate p0, Coordinate p1) {double dx p1.x - p0.x;double dy p1.y - p0.y;return Math.atan2(dy, dx); }返回与x轴正方向的夹…

java jts_Java Topology Suite (JTS)与空间数据模型

JTS是Java的处理地理数据的API&#xff0c;它提供以下功能&#xff1a; 实现了OGC关于简单要素SQL查询规范定义的空间数据模型 一个完整的、一致的、基本的二维空间算法的实现&#xff0c;包括二元运算(例如touch和overlap)和空间分析方法(例如intersection和buffer) 一个显示的…

java jts点到面的距离_jts-空间索引

前言&#xff1a; 如果您对JTS这三个词还是没有一个概念&#xff0c;那么推荐您关注一下sinoly的博客。这个我能够找到为数不多的关于jts的中文资料。 http://www.blogjava.net/sinoly/archive/2007/02/09/99042.html 下面这段话就是摘抄自sinoly老兄的博客&#xff1a; ......…

JTS Geometry关系判断和分析

关系判断 Geometry之间的关系有如下几种&#xff1a; 相等(Equals)&#xff1a; 几何形状拓扑上相等。 脱节(Disjoint)&#xff1a; 几何形状没有共有的点。 相交(Intersects)&#xff1a; 几何形状至少有一个共有点&#xff08;区别于脱节&#xff09; 接触(Touches)&a…

JTS Geometry用例分析

微信搜索&#xff1a;“二十同学” 公众号&#xff0c;欢迎关注一条不一样的成长之路 拓扑关系 GeometryTest import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryCollection; import…

JTS 笔记

简介 JTS由加拿大的VividSolutions公司开发&#xff0c;是一个用Java语言描述的几何拓扑套件&#xff0c;遵循OpenGIS的Simple Feature Specification&#xff0c;封装了2D几何类型和非常多的空间分析操作&#xff0c;而且包含了不少常见的计算几何算法实现。     JTS被广泛…

jts 简介、中文文档、中英对照文档 下载

jts 文档 下载链接&#xff08;含jar包、源码、pom&#xff09; 组件名称中文-文档-下载链接中英对照-文档-下载链接jts-1.13.jarjts-1.13-API文档-中文版.zipjts-1.13-API文档-中英对照版.zip jts 简介 JTS拓扑套件 JTS拓扑套件是一个用于建模和操作二维线性几何的API。它…

GeoTools——JTS的相关介绍和操作

GeoTools——JTS的相关介绍&#xff08;一&#xff09; JTS拓扑套件是GeoTools用于提供Geometry数据结构的实现&#xff0c;Geometry主要是指几何形状。 想要使用geoTools——JTS相关的操作可以导入以下的依赖<properties><geotools.version>17.1</geotools.ver…

java topo: 开源jtopo框架

java web 非本人研究方向&#xff0c;只是作为拓展知识涉猎范围 原文链接&#xff1a;http://www.jtopo.com/index.html jTopo是什么? jTopo&#xff08;Javascript Topology library)是一款完全基于HTML5 Canvas的关系、拓扑图形化界面开发工具包。 jTopo关注于数据的图形展…