用html+jq实现元素的拖动效果——js基础积累

news2025/2/25 4:53:04

html+jq实现元素的拖动效果

效果图如下:
在这里插入图片描述
将【item10】拖动到【item1】前面
在这里插入图片描述
直接上代码:

html部分

<ul id="sortableList">
  <li id="item1" class="w1" draggable="true">Item 1</li>
  <li id="item2" class="w2" draggable="true">Item 2</li>
  <li id="item3" class="w3" draggable="true">Item 3</li>
  <li id="item4" class="w1" draggable="true">Item 4</li>
  <li id="item5" class="w1" draggable="true">Item 5</li>
  <li id="item6" class="w2" draggable="true">Item 6</li>
  <li id="item7" class="w3" draggable="true">Item 7</li>
  <li id="item8" class="w1" draggable="true">Item 8</li>
  <li id="item9" class="w2" draggable="true">Item 9</li>
  <li id="item10" class="w3" draggable="true">Item 10</li>
</ul>

js部分

 <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script>
      document.addEventListener('DOMContentLoaded', function () {
        const sortableList = document.getElementById('sortableList');
        const items = sortableList.querySelectorAll('li');

        items.forEach((item) => {
          item.addEventListener('dragstart', dragStart);
          item.addEventListener('dragover', dragOver);
          item.addEventListener('drop', drop);
          item.addEventListener('dragenter', dragEnter);
          item.addEventListener('dragleave', dragLeave);
        });

        function dragStart(e) {
          e.dataTransfer.setData('text/plain', e.target.id);
          // setTimeout(() => {
          //     e.target.classList.add('hide');
          // }, 0);
          console.log('Drag started:', e.target.id);
        }

        function dragOver(e) {
          e.preventDefault();
          e.target.classList.add('over');
          console.log('Drag over:', e.target.id);
        }

        function dragEnter(e) {
          e.preventDefault();
          console.log('Drag enter:', e.target.id);
        }

        function dragLeave(e) {
          e.target.classList.remove('over');
          console.log('Drag leave:', e.target.id);
        }

        function drop(e) {
          e.preventDefault();
          const draggedItemId = e.dataTransfer.getData('text/plain');
          const draggedItem = document.getElementById(draggedItemId);
          const targetItem = e.target;

          if (targetItem !== draggedItem) {
            const targetIndex = Array.from(items).indexOf(targetItem);
            const draggedIndex = Array.from(items).indexOf(draggedItem);

            if (targetIndex > draggedIndex) {
              targetItem.parentNode.insertBefore(
                draggedItem,
                targetItem.nextSibling
              );
            } else {
              targetItem.parentNode.insertBefore(draggedItem, targetItem);
            }
          }

          e.target.classList.remove('over');
          draggedItem.classList.remove('hide');
          console.log('Drop:', e.target.id);
          console.log('在这里加检查宽度方法');
          checkWidth();
        }
      });

      // 检查宽度
      function checkWidth(first = true) {
        //清空空白块
        if (first) $('#sortableList li.box').remove();
        //盒子宽度
        let boxWidth = document.getElementById('sortableList').offsetWidth;
        //当前li行的宽度
        let rowLiWidth = 0;
        //循环li
        for (let i = 0; i < $('#sortableList li').length; i++) {
          var outerWidthWithMargin = $('#sortableList li')
            .eq(i)
            .outerWidth(true);
          var itemWidth = parseFloat(outerWidthWithMargin.toFixed(2));
          console.log(i, rowLiWidth, itemWidth);
          //当前li行的宽度+当前项宽度
          let RAW = rowLiWidth + itemWidth;
          //如果当前li行的宽度+当前项宽度大于盒子宽度,则添加空白块,并重新计算。
          //3是容错宽度。
          if (
            RAW >= boxWidth ||
            (RAW - boxWidth >= -3 && RAW - boxWidth <= 3)
          ) {
            //宽度大于盒子宽度,则添加空白块,并重新计算。
            if (RAW > boxWidth) {
              let thisWidth = boxWidth - rowLiWidth;
              if (thisWidth > 3) {
                $('#sortableList li')
                  .eq(i)
                  .before(`<li class="box" style="width:${thisWidth}px"></li>`);
                rowLiWidth = 0; //重新计算。
                checkWidth(false);
                break;
              }
            }
            rowLiWidth = 0; //重新计算。
          } else {
            rowLiWidth += itemWidth;
          }
          if (i == $('#sortableList li').length - 1) {
            let thisWidth = boxWidth - rowLiWidth;
            $('#sortableList li')
              .eq(i)
              .after(`<li class="box" style="width:${thisWidth}px"></li>`);
            break;
          }
        }
      }
    </script>

css部分

 <style>
      * {
        box-sizing: border-box;
      }
      #sortableList {
        list-style-type: none;
        padding: 0;
        display: flex;
        flex-wrap: wrap;
        position: relative;
      }
      #sortableList:after {
        border-top: none;
        border-left: none;
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        z-index: 0;
        pointer-events: none;
      }
      #sortableList:after,
      #sortableList li:after {
        content: '';
        border: 1px solid #eee;
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        z-index: 0;
        pointer-events: none;
      }
      #sortableList li:after {
        border-right: none;
        border-bottom: none;
      }
      #sortableList li {
        padding: 8px;
        background-color: #fff;
        cursor: move;
        position: relative;
      }
      #sortableList li.box {
        background-color: #fff;
      }
      #sortableList li.over {
        border: 2px dashed #000;
      }
      #sortableList li.w1 {
        width: 20%;
      }
      #sortableList li.w2 {
        width: 30%;
      }
      #sortableList li.w3 {
        width: 50%;
      }
      #sortableList li.hide {
        display: none;
      }
    </style>

完整版代码如下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
    <style>
      * {
        box-sizing: border-box;
      }
      #sortableList {
        list-style-type: none;
        padding: 0;
        display: flex;
        flex-wrap: wrap;
        position: relative;
      }
      #sortableList:after {
        border-top: none;
        border-left: none;
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        z-index: 0;
        pointer-events: none;
      }
      #sortableList:after,
      #sortableList li:after {
        content: '';
        border: 1px solid #eee;
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        z-index: 0;
        pointer-events: none;
      }
      #sortableList li:after {
        border-right: none;
        border-bottom: none;
      }
      #sortableList li {
        padding: 8px;
        background-color: #fff;
        cursor: move;
        position: relative;
      }
      #sortableList li.box {
        background-color: #fff;
      }
      #sortableList li.over {
        border: 2px dashed #000;
      }
      #sortableList li.w1 {
        width: 20%;
      }
      #sortableList li.w2 {
        width: 30%;
      }
      #sortableList li.w3 {
        width: 50%;
      }
      #sortableList li.hide {
        display: none;
      }
    </style>
  </head>
  <body>
    <ul id="sortableList">
      <li id="item1" class="w1" draggable="true">Item 1</li>
      <li id="item2" class="w2" draggable="true">Item 2</li>
      <li id="item3" class="w3" draggable="true">Item 3</li>
      <li id="item4" class="w1" draggable="true">Item 4</li>
      <li id="item5" class="w1" draggable="true">Item 5</li>
      <li id="item6" class="w2" draggable="true">Item 6</li>
      <li id="item7" class="w3" draggable="true">Item 7</li>
      <li id="item8" class="w1" draggable="true">Item 8</li>
      <li id="item9" class="w2" draggable="true">Item 9</li>
      <li id="item10" class="w3" draggable="true">Item 10</li>
    </ul>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script>
      document.addEventListener('DOMContentLoaded', function () {
        const sortableList = document.getElementById('sortableList');
        const items = sortableList.querySelectorAll('li');

        items.forEach((item) => {
          item.addEventListener('dragstart', dragStart);
          item.addEventListener('dragover', dragOver);
          item.addEventListener('drop', drop);
          item.addEventListener('dragenter', dragEnter);
          item.addEventListener('dragleave', dragLeave);
        });

        function dragStart(e) {
          e.dataTransfer.setData('text/plain', e.target.id);
          // setTimeout(() => {
          //     e.target.classList.add('hide');
          // }, 0);
          console.log('Drag started:', e.target.id);
        }

        function dragOver(e) {
          e.preventDefault();
          e.target.classList.add('over');
          console.log('Drag over:', e.target.id);
        }

        function dragEnter(e) {
          e.preventDefault();
          console.log('Drag enter:', e.target.id);
        }

        function dragLeave(e) {
          e.target.classList.remove('over');
          console.log('Drag leave:', e.target.id);
        }

        function drop(e) {
          e.preventDefault();
          const draggedItemId = e.dataTransfer.getData('text/plain');
          const draggedItem = document.getElementById(draggedItemId);
          const targetItem = e.target;

          if (targetItem !== draggedItem) {
            const targetIndex = Array.from(items).indexOf(targetItem);
            const draggedIndex = Array.from(items).indexOf(draggedItem);

            if (targetIndex > draggedIndex) {
              targetItem.parentNode.insertBefore(
                draggedItem,
                targetItem.nextSibling
              );
            } else {
              targetItem.parentNode.insertBefore(draggedItem, targetItem);
            }
          }

          e.target.classList.remove('over');
          draggedItem.classList.remove('hide');
          console.log('Drop:', e.target.id);
          console.log('在这里加检查宽度方法');
          checkWidth();
        }
      });

      // 检查宽度
      function checkWidth(first = true) {
        //清空空白块
        if (first) $('#sortableList li.box').remove();
        //盒子宽度
        let boxWidth = document.getElementById('sortableList').offsetWidth;
        //当前li行的宽度
        let rowLiWidth = 0;
        //循环li
        for (let i = 0; i < $('#sortableList li').length; i++) {
          var outerWidthWithMargin = $('#sortableList li')
            .eq(i)
            .outerWidth(true);
          var itemWidth = parseFloat(outerWidthWithMargin.toFixed(2));
          console.log(i, rowLiWidth, itemWidth);
          //当前li行的宽度+当前项宽度
          let RAW = rowLiWidth + itemWidth;
          //如果当前li行的宽度+当前项宽度大于盒子宽度,则添加空白块,并重新计算。
          //3是容错宽度。
          if (
            RAW >= boxWidth ||
            (RAW - boxWidth >= -3 && RAW - boxWidth <= 3)
          ) {
            //宽度大于盒子宽度,则添加空白块,并重新计算。
            if (RAW > boxWidth) {
              let thisWidth = boxWidth - rowLiWidth;
              if (thisWidth > 3) {
                $('#sortableList li')
                  .eq(i)
                  .before(`<li class="box" style="width:${thisWidth}px"></li>`);
                rowLiWidth = 0; //重新计算。
                checkWidth(false);
                break;
              }
            }
            rowLiWidth = 0; //重新计算。
          } else {
            rowLiWidth += itemWidth;
          }
          if (i == $('#sortableList li').length - 1) {
            let thisWidth = boxWidth - rowLiWidth;
            $('#sortableList li')
              .eq(i)
              .after(`<li class="box" style="width:${thisWidth}px"></li>`);
            break;
          }
        }
      }
    </script>
  </body>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2253314.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

单片机学习笔记 12. 定时/计数器_定时

更多单片机学习笔记&#xff1a;单片机学习笔记 1. 点亮一个LED灯单片机学习笔记 2. LED灯闪烁单片机学习笔记 3. LED灯流水灯单片机学习笔记 4. 蜂鸣器滴~滴~滴~单片机学习笔记 5. 数码管静态显示单片机学习笔记 6. 数码管动态显示单片机学习笔记 7. 独立键盘单片机学习笔记 8…

【乐企文件生成工程】搭建docker环境,使用docker部署工程

1、自行下载docker 2、自行下载docker-compose 3、编写Dockerfile文件 # 使用官方的 OpenJDK 8 镜像 FROM openjdk:8-jdk-alpine# 设置工作目录 WORKDIR ./app# 复制 JAR 文件到容器 COPY ../lq-invoice/target/lq-invoice.jar app.jar # 暴露应用程序监听的端口 EXPOSE 1001…

React基础知识三 router路由全指南

现在最新版本是Router6和Router5有比较大的变化&#xff0c;Router5和Router4变化不大&#xff0c;本文以Router6的写法为主&#xff0c;也会对比和Router5的不同。比较全面。 安装路由 npm i react-router-dom基本使用 有两种Router&#xff0c;BrowserRouter和HashRouter&…

【C#】书籍信息的添加、修改、查询、删除

文章目录 一、简介二、程序功能2.1 Book类属性&#xff1a;方法&#xff1a; 2.2 Program 类 三、方法&#xff1a;四、用户界面流程&#xff1a;五、程序代码六、运行效果 一、简介 简单的C#控制台应用程序&#xff0c;用于管理书籍信息。这个程序将允许用户添加、编辑、查看…

打造去中心化交易平台:公链交易所开发全解析

公链交易所&#xff08;Public Blockchain Exchange&#xff09;是指基于公有链&#xff08;如以太坊、波场、币安智能链等&#xff09;建立的去中心化交易平台。与传统的中心化交易所&#xff08;CEX&#xff09;不同&#xff0c;公链交易所基于区块链技术实现资产交换的去中心…

CLIP模型也能处理点云信息

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

关于NXP开源的MCU_boot的项目心得

MCU的启动流程细查 注意MCU上电第一个函数运行的就是Reset_Handler函数&#xff0c;下图是表示了这个函数做了啥事情&#xff0c;注意加强一下对RAM空间的段的印象&#xff0c;从上到下是栈&#xff0c;堆&#xff0c;.bss段&#xff0c;.data段。 bootloader的难点 固件完…

MySQL5.6升级MySQL5.7

升级方式介绍 08 数据库服务版本升级方法 5.6 – 5.7 – 8.0 数据库版本升级方法&#xff1a; Inplace-本地升级 步骤一&#xff1a;在同一台服务器中&#xff0c;需要部署高版本数据库服务实例步骤二&#xff1a;低版本数据库中的数据进行备份迁移&#xff0c;迁移到高版本…

怎么理解BeamSearch?

在大模型推理中&#xff0c;常会用到BeamSearch&#xff0c;本文就BeamSearch原理与应用理解展开讲解。 一、BeamSearch原理 Beam Search 是一种启发式搜索算法&#xff0c;常用于自然语言处理&#xff08;NLP&#xff09;和其他需要生成序列的任务中&#xff0c;比如机器翻译…

shodan2-批量查找CVE-2019-0708漏洞

声明&#xff01; 学习视频来自B站up主 泷羽sec 有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&#…

SciPy Optimize和 CVXPY对比

CVXPY和SciPy Optimize模块都是在Python中解决优化问题的强大工具&#xff0c;但它们是为不同类型的问题而设计的&#xff0c;具有不同的优点和局限性。本文对比两者的优缺点&#xff0c;阐述各自的应用场景&#xff0c;同时解释常用求解器&#xff0c;并给出实际示例进行说明。…

DevOps工程技术价值流:GitLab源码管理与提交流水线实践

在当今快速迭代的软件开发环境中&#xff0c;DevOps&#xff08;开发运维一体化&#xff09;已经成为提升软件交付效率和质量的关键。而GitLab&#xff0c;作为一个全面的开源DevOps平台&#xff0c;不仅提供了强大的版本控制功能&#xff0c;还集成了持续集成/持续交付(CI/CD)…

Android Studio 右侧工具栏 Gradle 不显示 Task 列表

问题&#xff1a; android studio 4.2.1版本更新以后AS右侧工具栏Gradle Task列表不显示&#xff0c;这里需要手动去设置 解决办法&#xff1a; android studio 2024.2.1 Patch 2版本以前的版本设置&#xff1a;依次打开 File -> Settings -> Experimental 选项&#x…

Linux详解:文件权限

文章目录 前言Linux文件权限基础文件成员与三组权限字符 权限的修改修改文件所有者总结 前言 在浩瀚的操作系统世界中&#xff0c;Linux以其开源、灵活和强大的特性&#xff0c;成为了服务器、开发环境以及众多个人用户的首选。而在Linux的众多特性中&#xff0c;文件权限机制…

SeggisV1.0 遥感影像分割软件【源代码】讲解

在此基础上进行二次开发&#xff0c;开发自己的软件&#xff0c;例如&#xff1a;【1】无人机及个人私有影像识别【2】离线使用【3】变化监测模型集成【4】个人私有分割模型集成等等&#xff0c;不管是您用来个人学习还是公司研发需求&#xff0c;都相当合适&#xff0c;包您满…

Spark常问面试题---项目总结

一、数据清洗&#xff0c;你都清洗什么&#xff1f;或者说 ETL 你是怎么做的&#xff1f; 我在这个项目主要清洗的式日志数据&#xff0c;日志数据传过来的json格式 去除掉无用的字段&#xff0c;过滤掉json格式不正确的脏数据 过滤清洗掉日志中缺少关键字段的数据&#xff…

数据结构4——栈和队列

目录 1.栈 1.1.栈的概念及结构 1.2栈的实现 2.队列 2.1队列的概念及结构 2.2队列的实现 1.栈 1.1.栈的概念及结构 栈&#xff1a;一种特殊的线性表&#xff0c;其只允许在固定的一端进行插入和删除元素操作。进行数据插入和删除操作的一段称为栈顶&#xff0c;另一端称为…

限定符使用

正则表达式的元字符一次一般只能匹配一个位置或一个字符,如果想要匹配零个、一个或多个字符时,则需要使用限定符。限定符用于指定允许特定字符或字符集自身重复出现的次数。常用限定符如下: <asp:TextBox [^>]> 正则表达式字符类[^>]匹配除过“>”之外的任何字…

【Python】Selenium模拟在输入框里,一个字一个字地输入文字

我们平常在使用Selenium模拟键盘输入内容&#xff0c;常用的是用send_keys来在输入框上输入字&#xff1a; 基本的输入方式&#xff1a; input_element driver.find_element(By.ID, searchBox) input_element.send_keys("我也爱你") #给骚骚的自己发个骚话不过这种…

Node.js 实战: 爬取百度新闻并序列化 - 完整教程

很多时候我们需要爬取一些公开的网页内容来做一些数据分析和统计。而多数时候&#xff0c;大家会用到python &#xff0c;因为实现起来很方便。但是其实Node.js 用来爬取网络内容&#xff0c;也是非常强大的。 今天我向大家介绍一下我自己写的一个百度新闻的爬虫&#xff0c;可…