前端原生js实现拖拽排课效果实例

2025-02-21 05:50

本文主要是介绍前端原生js实现拖拽排课效果实例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

《前端原生js实现拖拽排课效果实例》:本文主要介绍如何实现一个简单的课程表拖拽功能,通过HTML、CSS和JavaScript的配合,我们实现了课程项的拖拽、放置和显示功能,文中通过实例代码介绍的...

1. 效果展示

如图所示,页面左侧有一个包含不同课程(如语文、数学等)的列表,页面右侧是一个表格,表示一周内每天的不同时间段。用户可以通过拖拽左侧的课程到右侧的时间表中,来安排课程。

前端原生js实现拖拽排课效果实例

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>
                <kHrlsktr>
                    <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;
        }
www.chinasem.cn        .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="yChina编程u" 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>
            编程China编程        <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>
                &javascriptlt;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. 总结

到此这篇关于前端原生js实现拖拽排课效果的文章就介绍到这了,更多相关原生js拖拽排课效果内容请搜索China编程(www.chinasem.cn)以前的文章或继续浏览下面的相关文章希望大家以后多多支持China编程(www.chinasem.cn)!

这篇关于前端原生js实现拖拽排课效果实例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1153479

相关文章

C++中unordered_set哈希集合的实现

《C++中unordered_set哈希集合的实现》std::unordered_set是C++标准库中的无序关联容器,基于哈希表实现,具有元素唯一性和无序性特点,本文就来详细的介绍一下unorder... 目录一、概述二、头文件与命名空间三、常用方法与示例1. 构造与析构2. 迭代器与遍历3. 容量相关4

C++中悬垂引用(Dangling Reference) 的实现

《C++中悬垂引用(DanglingReference)的实现》C++中的悬垂引用指引用绑定的对象被销毁后引用仍存在的情况,会导致访问无效内存,下面就来详细的介绍一下产生的原因以及如何避免,感兴趣... 目录悬垂引用的产生原因1. 引用绑定到局部变量,变量超出作用域后销毁2. 引用绑定到动态分配的对象,对象

SpringBoot基于注解实现数据库字段回填的完整方案

《SpringBoot基于注解实现数据库字段回填的完整方案》这篇文章主要为大家详细介绍了SpringBoot如何基于注解实现数据库字段回填的相关方法,文中的示例代码讲解详细,感兴趣的小伙伴可以了解... 目录数据库表pom.XMLRelationFieldRelationFieldMapping基础的一些代

Java HashMap的底层实现原理深度解析

《JavaHashMap的底层实现原理深度解析》HashMap基于数组+链表+红黑树结构,通过哈希算法和扩容机制优化性能,负载因子与树化阈值平衡效率,是Java开发必备的高效数据结构,本文给大家介绍... 目录一、概述:HashMap的宏观结构二、核心数据结构解析1. 数组(桶数组)2. 链表节点(Node

Java AOP面向切面编程的概念和实现方式

《JavaAOP面向切面编程的概念和实现方式》AOP是面向切面编程,通过动态代理将横切关注点(如日志、事务)与核心业务逻辑分离,提升代码复用性和可维护性,本文给大家介绍JavaAOP面向切面编程的概... 目录一、AOP 是什么?二、AOP 的核心概念与实现方式核心概念实现方式三、Spring AOP 的关

vite搭建vue3项目的搭建步骤

《vite搭建vue3项目的搭建步骤》本文主要介绍了vite搭建vue3项目的搭建步骤,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录1.确保Nodejs环境2.使用vite-cli工具3.进入项目安装依赖1.确保Nodejs环境

Nginx搭建前端本地预览环境的完整步骤教学

《Nginx搭建前端本地预览环境的完整步骤教学》这篇文章主要为大家详细介绍了Nginx搭建前端本地预览环境的完整步骤教学,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录项目目录结构核心配置文件:nginx.conf脚本化操作:nginx.shnpm 脚本集成总结:对前端的意义很多

Python实现字典转字符串的五种方法

《Python实现字典转字符串的五种方法》本文介绍了在Python中如何将字典数据结构转换为字符串格式的多种方法,首先可以通过内置的str()函数进行简单转换;其次利用ison.dumps()函数能够... 目录1、使用json模块的dumps方法:2、使用str方法:3、使用循环和字符串拼接:4、使用字符

Linux下利用select实现串口数据读取过程

《Linux下利用select实现串口数据读取过程》文章介绍Linux中使用select、poll或epoll实现串口数据读取,通过I/O多路复用机制在数据到达时触发读取,避免持续轮询,示例代码展示设... 目录示例代码(使用select实现)代码解释总结在 linux 系统里,我们可以借助 select、

Linux挂载linux/Windows共享目录实现方式

《Linux挂载linux/Windows共享目录实现方式》:本文主要介绍Linux挂载linux/Windows共享目录实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录文件共享协议linux环境作为服务端(NFS)在服务器端安装 NFS创建要共享的目录修改 NFS 配