经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 软件/图像 » Git » 查看文章
07#Web 实战:实现 GitHub 个人主页项目拖拽排序
来源:cnblogs  作者:Enziandom  时间:2022/11/28 8:57:06  对本文有异议

实现效果图

image

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

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

思路构思

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

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

静态界面代码

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

  1. <div class="drop-box">
  2. <div class="drag-item item-0">
  3. <div class="ontology" draggable="true">Item 0</div>
  4. </div>
  5. <div class="drag-item item-1">
  6. <div class="ontology" draggable="true">Item 1</div>
  7. </div>
  8. <div class="drag-item item-2">
  9. <div class="ontology" draggable="true">Item 2</div>
  10. </div>
  11. <div class="drag-item item-3">
  12. <div class="ontology" draggable="true">Item 3</div>
  13. </div>
  14. </div>

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

  1. .drop-box {
  2. transition: all 0.5s ease-in-out;
  3. box-sizing: border-box;
  4. /* 在这里设置 drop-box 的高宽 */
  5. width: 420px;
  6. height: 300px;
  7. /* 在这里设置 drop-box 的高宽 */
  8. border-radius: 10px;
  9. border: 1px solid #cccccc;
  10. position: relative;
  11. }
  12. .drag-item {
  13. transition: all 0.5s ease-in-out;
  14. box-sizing: border-box;
  15. border-radius: 10px;
  16. border: 1px solid #cccccc;
  17. width: 200px;
  18. height: 50%;
  19. position: absolute;
  20. top: 0;
  21. left: 0;
  22. }
  23. .drag-item > div.ontology {
  24. width: 100%;
  25. height: 100%;
  26. }

构建二维数组

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

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

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

  1. let virtualGridElem = [];
  2. function initVirtualGrid(elem, init) {
  3. let elemIndex = 0;
  4. for (let rowIndex = 0; rowIndex < init.rowNum; rowIndex++) {
  5. virtualGridElem[rowIndex] = [];
  6. for (let colIndex = 0; colIndex < init.colNum; colIndex++) {
  7. $(elem[elemIndex]).attr("data-row-index", rowIndex);
  8. $(elem[elemIndex]).attr("data-col-index", colIndex);
  9. $(elem[elemIndex]).css({ width: init.width, height: init.height, transform: gridVals[rowIndex][colIndex] });
  10. initEvents(elem[elemIndex], elemIndex, rowIndex, colIndex);
  11. virtualGridElem[rowIndex][colIndex] = elem[elemIndex++];
  12. }
  13. }
  14. }

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

  1. let gridVals = [];
  2. function initGridVals(elNum, colNum, rowMaxWidth, colMaxWidth) {
  3. let rowNum = Math.ceil(elNum / colNum);
  4. let widthPerRow = rowMaxWidth / colNum;
  5. let heightPerCol = colMaxWidth / rowNum;
  6. let translateX = 0;
  7. for (let rowIndex = 0; rowIndex < rowNum; rowIndex++) {
  8. let translateY = 0;
  9. gridVals[rowIndex] = [];
  10. for (let colIndex = 0; colIndex < colNum; colIndex++) {
  11. gridVals[rowIndex][colIndex] = `translate(${translateY}px, ${translateX}px)`;
  12. translateY += widthPerRow;
  13. }
  14. translateX += heightPerCol;
  15. }
  16. return {
  17. width: widthPerRow,
  18. height: heightPerCol,
  19. rowNum: rowNum,
  20. colNum: colNum
  21. };
  22. }

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

  1. let dragItem = $(".drop-box").children(".drag-item");
  2. initVirtualGrid(dragItem, initGridVals($(dragItem).length, 2, 420, 300));

拖拽排序功能

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

  1. function initEvents(elem, index, rowIndex, colIndex) {
  2. // drop 是获取拖拽目标元素
  3. $(elem).on("drop", e => {
  4. e.preventDefault();
  5. $(virtualGridElem[rowIndex][colIndex]).css({ transform: gridVals[currRowIndex][currColIndex] });
  6. $(virtualGridElem[currRowIndex][currColIndex]).css({ transform: gridVals[rowIndex][colIndex] });
  7. // let tempTargetGridVals = gridVals[currRowIndex][currColIndex];
  8. // gridVals[currRowIndex][currColIndex] = gridVals[rowIndex][colIndex];
  9. // gridVals[rowIndex][colIndex] = tempTargetGridVals;
  10. [gridVals[currRowIndex][currColIndex], gridVals[rowIndex][colIndex]] = [gridVals[rowIndex][colIndex], gridVals[currRowIndex][currColIndex]];
  11. });
  12. // 必须写这一段代码,否则 drop 监听器不生效
  13. $(elem).on("dragover", e => {
  14. e.preventDefault();
  15. });
  16. // drag 相关的监听是对拖拽元素目标有效的
  17. let ontology = $(elem).children(".ontology");
  18. $(ontology).on("dragstart", e => {
  19. currRowIndex = rowIndex;
  20. currColIndex = colIndex;
  21. $(elem).css({ opacity: "0.5" });
  22. });
  23. $(ontology).on("dragend", e => {
  24. $(elem).css({ opacity: "1" });
  25. });
  26. }

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

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

  1. let x = 1, y = 2;
  2. [x, y] = [y, x]

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

结束语

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

原文链接:https://www.cnblogs.com/Enziandom/p/16931129.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号