【前端动效】原生js实现拖拽排课效果
目录
1. 效果展示
2. 效果分析
2.1 关键点
2.2 实现方法
3. 代码实现
3.1 html部分
3.2 css部分
3.3 js部分
3.4 完整代码
4. 总结
1. 效果展示
如图所示,页面左侧有一个包含不同课程(如语文、数学等)的列表,页面右侧是一个表格,表示一周内每天的不同时间段。用户可以通过拖拽左侧的课程到右侧的时间表中,来安排课程。

2. 效果分析
目标:鼠标摁下左侧某一科目,拖拽到右侧某一位置放下,拖拽的课程就会嵌入到课表框当中
2.1 关键点
(1) 拖拽与放置逻辑的实现
(2) HTML与CSS布局的设计
2.2 实现方法
(1) 将拖拽过程分为 开始拖拽、允许放置、放置三部分分析。
(2) 页面主要由两部分组成——左侧是可拖动的课程项列表,右侧是一个表格,用于显示每周的时间安排。每个课程项都设定了 draggable = "true" 属性,使其可以被拖动。表格中的 <td> 元素(不包括第一列)是可以放置课程的目标区域。
(3) 通过 CSS 确保页面居中显示,并设置了 .box 容器的尺寸和边框。.left 和 .right 分别代表课程项列表和时间表的位置和大小。
3. 代码实现
接下来我会一步一步解说每段关键代码的含义。
3.1 html部分
<div class="box"><div class="left"><div class="yu" draggable="true">语文</div><div class="shu" draggable="true">数学</div><div class="ying" draggable="true">英语</div><div class="wu" draggable="true">物理</div><div class="hua" draggable="true">化学</div><div class="sheng" draggable="true">生物</div></div><div class="right"><table><tr><th>时间/星期</th><th>星期一</th><th>星期二</th><th>星期三</th><th>星期四</th><th>星期五</th></tr><tr><td>08:00-09:00</td><td></td><td></td><td></td><td></td><td></td></tr><tr><td>10:00-11:00</td><td></td><td></td><td></td><td></td><td></td></tr><tr><td>11:00-12:00</td><td></td><td></td><td></td><td></td><td></td></tr><tr><td>12:00-13:00</td><td></td><td></td><td></td><td></td><td></td></tr><tr><td>14:00-15:00</td><td></td><td></td><td></td><td></td><td></td></tr><tr><td>15:00-16:00</td><td></td><td></td><td></td><td></td><td></td></tr></table></div></div>
左侧是课程列表, 该部分包含六个 <div> 元素,每个元素代表一门课程(如语文、数学等),并赋予了 draggable = "true" 属性,这意味着这些课程项可以被拖动。
右侧是时间表,提供了五个工作日(周一至周五)和六个上课时段的时间框架,使得用户可以直观地安排每周的课程。
3.2 css部分
.left {width: 150px;display: flex;flex-direction: column;justify-content: space-between;gap: .7rem;}.left > div {width: 100%;height: 50px;border: 1px solid black;text-align: center;line-height: 50px;font-weight: bold;letter-spacing: 4px;cursor: move;}.yu { background: lawngreen; }.shu { background: skyblue; }.ying { background: mediumslateblue; }.wu { background: aqua; }.hua { background: violet; }.sheng { background: navajowhite; }.right {width: 750px;height: 400px;overflow: auto;}
css部分没什么好说的,按照自己的喜好随意编写即可。
3.3 js部分
const draggables = document.querySelectorAll('.left > div');
const droppables = document.querySelectorAll('.right td:not(:first-child)');
获取所有可拖动的课程项 和 所有可放置课程的时间段单元格(不包括第一列)。
draggables.forEach(draggable => {draggable.addEventListener('dragstart', e => {e.dataTransfer.setData('text/plain', e.target.className);e.dataTransfer.dropEffect = 'move';});});
拖拽开始::当用户开始拖动一个课程项时,浏览器触发 dragstart 事件。在这个事件处理函数中,我们使用 setData 方法将被拖拽元素的类名作为数据存储在 Datatransfer 对象中。同时,设置drapEffect 属性为 ‘move’,以表明这是一个移动操作。
droppables.forEach(droppable => {droppable.addEventListener('dragover', e => {e.preventDefault();e.dataTransfer.dropEffect = 'move';});
});
允许放置: 当拖拽元素经过目标单元格时,浏览器会触发 dragover 事件。默认情况下,浏览器会阻止这个事件,所以我们需要调用 preventDefault() 来允许放置。同样地,我们设置 dropEffect为 ‘move’,以便与 dragstart 中的设置相匹配。
droppable.addEventListener('drop', e => {e.preventDefault();const draggedItemClass = e.dataTransfer.getData('text/plain');const draggedItem = document.querySelector(`.${draggedItemClass}`);if (e.target.tagName === 'TD') {e.target.textContent = draggedItem.textContent;e.target.style.backgroundColor = window.getComputedStyle(draggedItem).backgroundColor;}
});
放置:当用户释放鼠标按钮,拖拽元素被放置到目标单元格时,浏览器触发 drap 事件。在这个事件处理函数中,我们获取之前存储的数据(即课程项的类名),找到对应的课程项,并将其内容和背景颜色复制到目标单元格中。
3.4 完整代码
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>拖拽实现排课</title><style>body {margin: 0;padding: 0;display: flex;justify-content: center;align-items: center;height: 100vh;background-color: #f0f0f0;}.box {width: 1000px;height: 600px;border: 1px solid red;display: flex;justify-content: space-between;align-items: center;padding: 20px;box-sizing: border-box;}.left {width: 150px;display: flex;flex-direction: column;justify-content: space-between;gap: .7rem;}.left > div {width: 100%;height: 50px;border: 1px solid black;text-align: center;line-height: 50px;font-weight: bold;letter-spacing: 4px;cursor: move;}.yu { background: lawngreen; }.shu { background: skyblue; }.ying { background: mediumslateblue; }.wu { background: aqua; }.hua { background: violet; }.sheng { background: navajowhite; }.right {width: 750px;height: 400px;overflow: auto;}table {width: 100%;border-collapse: collapse;}th, td {width: 120px;height: 50px;border: 1px solid black;text-align: center;}td {cursor: pointer;}</style>
</head>
<body><div class="box"><div class="left"><div class="yu" draggable="true">语文</div><div class="shu" draggable="true">数学</div><div class="ying" draggable="true">英语</div><div class="wu" draggable="true">物理</div><div class="hua" draggable="true">化学</div><div class="sheng" draggable="true">生物</div></div><div class="right"><table><tr><th>时间/星期</th><th>星期一</th><th>星期二</th><th>星期三</th><th>星期四</th><th>星期五</th></tr><tr><td>08:00-09:00</td><td></td><td></td><td></td><td></td><td></td></tr><tr><td>10:00-11:00</td><td></td><td></td><td></td><td></td><td></td></tr><tr><td>11:00-12:00</td><td></td><td></td><td></td><td></td><td></td></tr><tr><td>12:00-13:00</td><td></td><td></td><td></td><td></td><td></td></tr><tr><td>14:00-15:00</td><td></td><td></td><td></td><td></td><td></td></tr><tr><td>15:00-16:00</td><td></td><td></td><td></td><td></td><td></td></tr></table></div></div><script>// 获取所有可拖动的课程项const draggables = document.querySelectorAll('.left > div');// 获取所有可放置课程的时间段单元格(不包括第一列)const droppables = document.querySelectorAll('.right td:not(:first-child)');// 添加拖拽开始事件监听器draggables.forEach(draggable => {draggable.addEventListener('dragstart', e => {e.dataTransfer.setData('text/plain', e.target.className);e.dataTransfer.dropEffect = 'move';});});// 添加拖拽进入和放置事件监听器droppables.forEach(droppable => {droppable.addEventListener('dragover', e => {e.preventDefault();e.dataTransfer.dropEffect = 'move';});droppable.addEventListener('drop', e => {e.preventDefault();const draggedItemClass = e.dataTransfer.getData('text/plain');const draggedItem = document.querySelector(`.${draggedItemClass}`);if (e.target.tagName === 'TD') {e.target.textContent = draggedItem.textContent;e.target.style.backgroundColor = window.getComputedStyle(draggedItem).backgroundColor;}});});</script>
</body>
</html>
4. 总结
以上即是实现拖拽排课动效的全部内容。如果对您有所帮助,不妨点赞、关注+收藏,下次不迷路😀。
更多前端动效点击下方链接↓ ↓ ↓
前端动效_借来一夜星光的博客-CSDN博客
相关文章:
【前端动效】原生js实现拖拽排课效果
目录 1. 效果展示 2. 效果分析 2.1 关键点 2.2 实现方法 3. 代码实现 3.1 html部分 3.2 css部分 3.3 js部分 3.4 完整代码 4. 总结 1. 效果展示 如图所示,页面左侧有一个包含不同课程(如语文、数学等)的列表,页面右侧…...
C#使用OpenTK绘制3D可拖动旋转图形三棱锥
接上篇,绘制着色矩形 C#使用OpenTK绘制一个着色矩形-CSDN博客 上一篇安装OpenTK.GLControl后,这里可以直接拖动控件GLControl 我们会发现GLControl继承于UserControl //// 摘要:// OpenGL-aware WinForms control. The WinForms designer will always call the default//…...
排序的本质、数据类型及算法选择
排序的本质、数据类型及算法选择 一、排序的本质二、排序的数据类型三、排序算法的选择依据 前两天老金写了篇 “十大排序简介”,有点意犹未尽,这一回老金想把排序连根拔起,从排序的本质说道说道。 一、排序的本质 从字面上理解,…...
Python的列表基础知识点(超详细流程)
目录 一、环境搭建 二、列表 2.1 详情 2.2 列表定义 2.3 列表长度 2.4 列表索引 2.5 切片索引 2.6 添加 2.7 插入 2.8 剔除 2.8.1 pop方法 2.8.2 del方法 2.9 任何数据类型 2.10 拼接 2.10.1 “” 2.10.2 “*” 2.11 逆序 编辑 2.12 计算出现次数 2.13 排序…...
HarmonyOS鸿蒙开发 弹窗及加载中指示器HUD功能实现
HarmonyOS鸿蒙开发 弹窗及加载中指示器HUD功能实现 最近在学习鸿蒙开发过程中,阅读了官方文档,在之前做flutter时候,经常使用overlay,使用OverlayEntry加入到overlayState来做添加悬浮按钮、提示弹窗、加载中指示器、加载失败的t…...
【Ubuntu与Linux操作系统:一、Ubuntu安装与基本使用】
第1章 Ubuntu安装与基本使用 1.1 Linux与Ubuntu Linux是一种开源、类Unix操作系统内核,拥有高稳定性和强大的网络功能。由于其开源性和灵活性,Linux被广泛应用于服务器、嵌入式设备以及桌面环境中。 Ubuntu是基于Debian的一个流行Linux发行版…...
React 元素渲染
React 元素渲染 React 是一个用于构建用户界面的 JavaScript 库,它允许开发人员创建大型应用程序,这些应用程序可以随着时间的推移而高效地更新和渲染。React 的核心概念之一是元素渲染,它描述了如何将 JavaScript 对象转换为 DOM࿰…...
【2024年华为OD机试】 (C卷,100分)- 括号匹配(Java JS PythonC/C++)
一、问题描述 题目描述 给定一个字符串,里边可能包含“()”、“[]”、“{}”三种括号,请编写程序检查该字符串中的括号是否成对出现,且嵌套关系正确。 若括号成对出现且嵌套关系正确,或该字符串中无括号字符,输出&am…...
解锁企业数字化转型新力量:OpenCoze(开源扣子)
在当今数字化浪潮席卷之下,企业对于高效管理和协同运作的需求愈发迫切,而开源技术正逐渐成为众多企业破局的关键利器。今天,想给大家介绍一款极具潜力的开源项目 ——OpenCoze,中文名称 “开源扣子”。 一、OpenCoze 是什么&…...
【网络云SRE运维开发】2025第2周-每日【2025/01/12】小测-【第12章 rip路由协议】理论和实操考试题解析
文章目录 选择题答案及解析理论题答案及解析实操题答案及解析下一步进阶 选择题答案及解析 RIP路由协议是基于哪种算法的动态路由协议? 答案:B. 距离矢量算法解析:链路状态算法用于OSPF等协议;最小生成树算法主要用于生成树协议&…...
【微服务】8、分布式事务 ( XA 和 AT )
文章目录 利用Seata解决分布式事务问题(XA模式)AT模式1. AT模式原理引入2. AT模式执行流程与XA模式对比3. AT模式性能优势及潜在问题4. AT模式数据一致性解决方案5. AT模式一阶段操作总结6. AT模式二阶段操作分析7. AT模式整体特点8. AT模式与XA模式对比…...
CVE-2025-22777 (CVSS 9.8):WordPress | GiveWP 插件的严重漏洞
漏洞描述 GiveWP 插件中发现了一个严重漏洞,该插件是 WordPress 最广泛使用的在线捐赠和筹款工具之一。该漏洞的编号为 CVE-2025-22777,CVSS 评分为 9.8,表明其严重性。 GiveWP 插件拥有超过 100,000 个活跃安装,为全球无数捐赠平…...
TypeScript Jest 单元测试 搭建
NPM TypeScript 项目搭建 创建目录 mkdir mockprojectcd mockproject初始化NPM项目 npm init -y安装TypeScript npm i -D typescript使用VSCode 打开项目 创建TS配置文件tsconfig.json {"compilerOptions": {"target": "es5","module&…...
基于 SSH 的任务调度系统
文末附有完整项目代码 在当今科技飞速发展的时代,任务调度系统的重要性日益凸显。本文将详细介绍一个基于 SSH(SpringStruts2Hibernate)的任务调度系统的设计与实现。 一、系统概述 本系统旨在改变传统人工任务调度方式,通过计算…...
filestream安装使用全套+filebeat的模块用法
1 filestream介绍 官方宣布:输入类型为log在filebeat7.16版本已经弃用了 Filestream 是 Filebeat 中的一种 输入类型(Input),用于处理日志文件的读取。它是为了取代 Filebeat 中传统的 log 输入(Input)设…...
java项目之房屋租赁系统源码(springboot+mysql+vue)
项目简介 房屋租赁系统实现了以下功能: 房屋租赁系统的主要使用者分为: 系统管理:个人中心、房屋信息管理、预约看房管理、合同信息管理、房屋报修管理、维修处理管理、房屋评价管理等模块的查看及相应操作; 房屋信息管理&#…...
sap mm学习笔记
1. 业务流程 2. 组织架构 3. 物料主数据 4.采购主数据 5. 采购管理 6. 库存管理 7.物料主数据 8. 采购申请 ME51N...
代码随想录_链表
代码随想录02 链表 203.移除链表元素 力扣题目链接(opens new window) 题意:删除链表中等于给定值 val 的所有节点。 示例 1: 输入:head [1,2,6,3,4,5,6], val 6 输出:[1,2,3,4,5] 示例 2: 输入:he…...
EF Code 并发控制
【悲观控制】 不推荐用,EF Core 没有封装悲观并发控制的使用,需要使用原生Sql来使用悲观并发控制 一般使用行锁、表锁等排他锁对资源进行锁定,同时只有一个使用者操作被锁定的资源 拿sql server举例,可以使用表所、或者行所解决…...
ceph fs status 输出详解
ceph fs status 命令用于显示 Ceph 文件系统的状态信息,其中各列的含义如下: RANK:元数据服务器(MDS)的等级或标识符。 STATE:MDS 的当前状态,例如 active(活跃)、stan…...
linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
新能源汽车智慧充电桩管理方案:新能源充电桩散热问题及消防安全监管方案
随着新能源汽车的快速普及,充电桩作为核心配套设施,其安全性与可靠性备受关注。然而,在高温、高负荷运行环境下,充电桩的散热问题与消防安全隐患日益凸显,成为制约行业发展的关键瓶颈。 如何通过智慧化管理手段优化散…...
深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南
🚀 C extern 关键字深度解析:跨文件编程的终极指南 📅 更新时间:2025年6月5日 🏷️ 标签:C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言🔥一、extern 是什么?&…...
OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
tomcat入门
1 tomcat 是什么 apache开发的web服务器可以为java web程序提供运行环境tomcat是一款高效,稳定,易于使用的web服务器tomcathttp服务器Servlet服务器 2 tomcat 目录介绍 -bin #存放tomcat的脚本 -conf #存放tomcat的配置文件 ---catalina.policy #to…...
苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会
在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...
HTML前端开发:JavaScript 获取元素方法详解
作为前端开发者,高效获取 DOM 元素是必备技能。以下是 JS 中核心的获取元素方法,分为两大系列: 一、getElementBy... 系列 传统方法,直接通过 DOM 接口访问,返回动态集合(元素变化会实时更新)。…...
Python竞赛环境搭建全攻略
Python环境搭建竞赛技术文章大纲 竞赛背景与意义 竞赛的目的与价值Python在竞赛中的应用场景环境搭建对竞赛效率的影响 竞赛环境需求分析 常见竞赛类型(算法、数据分析、机器学习等)不同竞赛对Python版本及库的要求硬件与操作系统的兼容性问题 Pyth…...
书籍“之“字形打印矩阵(8)0609
题目 给定一个矩阵matrix,按照"之"字形的方式打印这个矩阵,例如: 1 2 3 4 5 6 7 8 9 10 11 12 ”之“字形打印的结果为:1,…...
