实现效果图

GitHub 和 Gitee 个人主页中可以对自己的项目进行拖拽排序,于是我就想自己实现一个。本随笔只是记录一下大概的实现思路,如果感兴趣的小伙伴可以通过代码和本随笔的说明去理解实现过程。我的 GiteeGitHub 地址。

在线浏览地址:11.拖拽排序,里面还有更多的例子。

思路构思

要实现元素拖拽可替换位置,就必须要锁定每一个元素的具体位置,且要直到两个元素的 transform: translate()。从代码上看,这是一个二维数组。从界面上看,就是一个网格布局。06#Web 实战:实现可滑动的标签页是通过一维数组实现的。

元素的布局不可能通过display: grid来进行,得用transform: translate(),实现元素得平移,且需要使用绝对和相对定位。

静态界面代码

这里给出初始的静态界面代码,draggable 表示开启这个元素的可拖拽功能:

<div class="drop-box">
<div class="drag-item item-0">
<div class="ontology" draggable="true">Item 0</div>
</div>
<div class="drag-item item-1">
<div class="ontology" draggable="true">Item 1</div>
</div>
<div class="drag-item item-2">
<div class="ontology" draggable="true">Item 2</div>
</div>
<div class="drag-item item-3">
<div class="ontology" draggable="true">Item 3</div>
</div>
</div>

老样子,我喜欢把不必要的代码给省略掉,如果样式不全,去我的仓库复制:

.drop-box {
transition: all 0.5s ease-in-out;
box-sizing: border-box;
/* 在这里设置 drop-box 的高宽 */
width: 420px;
height: 300px;
/* 在这里设置 drop-box 的高宽 */
border-radius: 10px;
border: 1px solid #cccccc;
position: relative;
} .drag-item {
transition: all 0.5s ease-in-out;
box-sizing: border-box;
border-radius: 10px;
border: 1px solid #cccccc;
width: 200px;
height: 50%;
position: absolute;
top: 0;
left: 0;
} .drag-item > div.ontology {
width: 100%;
height: 100%;
}

构建二维数组

拖拽每一个元素不代表真实地改变了 DOM 所在的位置。给这些元素设置监听器,并获取 index,拖拽之后都不会影响它的索引值。

上面给的 HTML 结构,在界面上生成之后,从 1 ~ 4 这样的序列是不会改变的,即便是我们修改了它的 translate(平移元素)之后,也不会影响它原本在 DOM 树上的顺序。

为了方便在代码中修改元素的transform: translate(),我们需要在页面载入时就虚拟化这些元素到二维数组中。元素虚拟化进二维数组的目的是让编程更加易于使用。

let virtualGridElem = [];

function initVirtualGrid(elem, init) {
let elemIndex = 0;
for (let rowIndex = 0; rowIndex < init.rowNum; rowIndex++) {
virtualGridElem[rowIndex] = [];
for (let colIndex = 0; colIndex < init.colNum; colIndex++) {
$(elem[elemIndex]).attr("data-row-index", rowIndex);
$(elem[elemIndex]).attr("data-col-index", colIndex);
$(elem[elemIndex]).css({ width: init.width, height: init.height, transform: gridVals[rowIndex][colIndex] });
initEvents(elem[elemIndex], elemIndex, rowIndex, colIndex);
virtualGridElem[rowIndex][colIndex] = elem[elemIndex++];
}
}
}

在虚拟化之前,需要获得这个界面中的网格信息,即网格有多少行,每一行有多少列。

let gridVals = [];

function initGridVals(elNum, colNum, rowMaxWidth, colMaxWidth) {
let rowNum = Math.ceil(elNum / colNum);
let widthPerRow = rowMaxWidth / colNum;
let heightPerCol = colMaxWidth / rowNum; let translateX = 0;
for (let rowIndex = 0; rowIndex < rowNum; rowIndex++) {
let translateY = 0;
gridVals[rowIndex] = [];
for (let colIndex = 0; colIndex < colNum; colIndex++) {
gridVals[rowIndex][colIndex] = `translate(${translateY}px, ${translateX}px)`;
translateY += widthPerRow;
}
translateX += heightPerCol;
} return {
width: widthPerRow,
height: heightPerCol,
rowNum: rowNum,
colNum: colNum
};
}

到目前为止,得到了两个重要的二维数组:virtualGridElem 和 gridVals。virtualGridElem 不会被改变,一直保持原有的位置,与实际的可拖拽元素的 DOM 树保持一致。gridVals 会与 virtualGridElem 发生出入,会根据操作而修改。

let dragItem = $(".drop-box").children(".drag-item");

initVirtualGrid(dragItem, initGridVals($(dragItem).length, 2, 420, 300));

拖拽排序功能

拖拽在 HTML5 就已经存在,drop、dragover、dragstart、dragend 都是实现本案例中最重要的几个监听事件。其中 drop 表示可拖拽元素到目标元素之后的元素,即 item1 拖拽到 item2 之后,获取 item2 的元素。

function initEvents(elem, index, rowIndex, colIndex) {
// drop 是获取拖拽目标元素
$(elem).on("drop", e => {
e.preventDefault();
$(virtualGridElem[rowIndex][colIndex]).css({ transform: gridVals[currRowIndex][currColIndex] });
$(virtualGridElem[currRowIndex][currColIndex]).css({ transform: gridVals[rowIndex][colIndex] });
// let tempTargetGridVals = gridVals[currRowIndex][currColIndex];
// gridVals[currRowIndex][currColIndex] = gridVals[rowIndex][colIndex];
// gridVals[rowIndex][colIndex] = tempTargetGridVals;
[gridVals[currRowIndex][currColIndex], gridVals[rowIndex][colIndex]] = [gridVals[rowIndex][colIndex], gridVals[currRowIndex][currColIndex]];
}); // 必须写这一段代码,否则 drop 监听器不生效
$(elem).on("dragover", e => {
e.preventDefault();
}); // drag 相关的监听是对拖拽元素目标有效的
let ontology = $(elem).children(".ontology"); $(ontology).on("dragstart", e => {
currRowIndex = rowIndex;
currColIndex = colIndex;
$(elem).css({ opacity: "0.5" });
}); $(ontology).on("dragend", e => {
$(elem).css({ opacity: "1" });
});
}

代码最多的是 drop 事件,在开始拖拽时,也就是获取拖拽的元素信息,在这里我们要把这个拖拽的元素透明度调低一点,表示被拖拽中的元素。之后,记录改拖拽元素的二维索引值,rowIndex、colIndex,记录为 currXxxIndex。

在拖拽完成之后,就要触发 drop 事件。drop 事件中,对 gridVals 进行值的交替。ES6 中解构赋值不需要中间变量临时存储,就可以实现值交换:

let x = 1, y = 2;

[x, y] = [y, x]

替换之后,x = 2,y = 1。

结束语

具体实现过程请去看我仓库中的代码 GiteeGitHub 地址。喜欢的话,请点个赞再走哦!后续带来更多的 Web 实践。

07#Web 实战:实现 GitHub 个人主页项目拖拽排序的更多相关文章

  1. HTML5实战与剖析之原生拖拽(四可拖动dragable属性和其他成员)

    可拖动dragable属性 之前我们已经为大家介绍过几篇有关HTML5中原生拖拽的相关知识了.今天为大家介绍HTML5拖拽中的其他一些小东东,闲话不多说赶快一起看看吧. 在默认情况下,链接.文本和图像 ...

  2. HTML5实战与剖析之原生拖拽(一拖拽历史概述)

    提起拖拽,我就想起了在JavaScript培训的时候一个非常好玩的效果,那就是拖拽了.可以用鼠标任意拖拽着一个物体到任何你想去的地方. 最早拥有JavaScript拖拽功能的是IE4浏览器.当时,网页 ...

  3. React造轮子:拖拽排序组件「Dragact」

    先来一张图看看: 项目地址:Github地址 (无耻求星!) 在线观看(第一次加载需要等几秒):预览地址 说起来不容易,人在国外没有过年一说,但是毕竟也是中国年,虽然不放假,但是家里总会主内一顿丰盛的 ...

  4. RecyclerViewItemTouchHelperDemo【使用ItemTouchHelper进行拖拽排序功能】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 记录使用ItemTouchHelper对Recyclerview进行拖拽排序功能的实现. 效果图 代码分析 ItemTouchHel ...

  5. html5 Sortable.js 拖拽排序源码分析

    最近公司项目经常用到一个拖拽 Sortable.js插件,所以有空的时候看了 Sortable.js 源码,总共1300多行这样,写的挺完美的.   本帖属于原创,转载请出名出处. 官网http:// ...

  6. jQuery可拖拽排序列表jquery-sortable-lists

    jquery-sortable-lists可以通过鼠标进行拖动排列树型菜单,可以定义某个列表元素是否拖动,拖动后回调,点击可以折叠树型结点,可以用来在后台模仿wordpress后台拖动菜单,实现多级菜 ...

  7. 使用knockout-sortable实现对自定义菜单的拖拽排序

    在开始之前,照例,我们先看效果和功能实现. 关于自定义菜单的实现,这里就不多说了,需要了解的请访问:http://www.cnblogs.com/codelove/p/4838766.html 这里需 ...

  8. RecyclerView拖拽排序;

    效果就是这样,RecyclerView列表可拖拽排序,可删除,可添加: RecyclerView给我们提供了一个手势器: ItemTouchHelper helper = new ItemTouchH ...

  9. ListView 多行拖拽排序

    核心代码:修改ListView的属性,及绑定事件 // 初始化listView1. private void InitializeListView() { listView1.AllowDrop = ...

  10. react 拖拽排序---原生

    定义css, 两个动画 .drag-up { -webkit-animation: dragup ease 0.2s 1; animation: dragup ease 0.2s 1; -webkit ...

随机推荐

  1. G&GH04 本地连接至远程

    注意事项与声明 平台: Windows 10 作者: JamesNULLiu 邮箱: jamesnulliu@outlook.com 博客: https://www.cnblogs.com/james ...

  2. SQL Server如何精准匹配字符中的字符,绝对匹配。

    举例: 我现在是需要查询这字段里包含1的数据 我如果直接charindex,那么11,12也会被包含. 解决(1): SELECT * FROM ( SELECT '1,2,12,111' AS st ...

  3. 数据火器库八卦系列之瑞士军刀随APP携带的SQLite

    来源:云数据库技术 数据库打工仔喃喃自语的八卦历史 1. 为导弹巡洋舰设计,用在手机上的数据库 2. Small and Simple, and Better 3. 如何看出是自己的娃:产品定位,特点 ...

  4. 【题解】CF1720C

    题意简述 给你一个 01 矩阵,每一次你可以在这个矩阵中找到一个 \(L\) 型,将它全部变成 0.\(L\) 型的定义是在一个 \(2\times2\) 矩阵中,除开一个角之外的图形,其中必须包含至 ...

  5. Linux系统安装宝塔面板教程

    # Linux系统宝塔安装教程 注意:安装宝塔面板的前提条件 首先要有一台服务器或者使用linux系统的虚拟机. 安装前请确保是[全新的机器].必须是没装过其它环境的新系统,如Apache/Nginx ...

  6. 齐博x1到底是怎么的存在?

    齐博X1是齐博软件基于thinkphp5开发的内容管理系统,拓展性非常强,后台一键升级,后台提供丰富的频道模块云市插件市场.风格市场.钩子市场,所有都是一键在线安装. 系统已经对接好QQ.微信登录,同 ...

  7. 使用 etcdadm 快速、弹性部署 etcd 集群

    Etcd 是一个可靠的分布式键值存储, 常用于分布式系统关键数据的存储:而 etcdadm 是一个用于操作 etcd 集群的命令行工具,它可以轻松创建集群.向现有集群添加成员.从现有集群中删除成员等操 ...

  8. 知识图谱顶会论文(KDD-2022) kgTransformer:复杂逻辑查询的预训练知识图谱Transformer

    论文标题:Mask and Reason: Pre-Training Knowledge Graph Transformers for Complex Logical Queries 论文地址: ht ...

  9. 七、kubernetes污点和容忍

    Kubernetes污点和容忍 一.Taint 和 Toleration介绍 节点亲和性,是 pod 的一种属性(偏好或硬性要求),它使 pod 被吸引到一类特定的节点.Taint 则相反,它使节点能 ...

  10. 深度剖析Java的volatile实现原理,再也不怕面试官问了

    上篇文章我们讲了synchronized的用法和实现原理,我们总爱说synchronized是重量级锁,volatile是轻量级锁.为什么volatile是轻量级锁,体现在哪些方面?以及volatil ...