前端实现可拖拽课程表【纯HTML、CSS、JS】

news2024/10/6 16:29:53

前言

hello,今天实现点小动画,帮助学习理解Web api的拖拽效果,这里实现的是可拖拽的课程表!#

效果图

在这里插入图片描述
附:作者没钱去除水印,就这样看一下简单的看一下效果吧!

实现前言知识

这里我使用事件委托,统一将拖拽事件委托给父元素contaniner。

实现该元素可拖拽

这里我们使用dom的一个属性draggable,将该属性设置为true,即可拖拽

   <div  draggable="true"  class="color-1 item">语文</div>

拖拽开始事件

container.ondragstart,记录拖拽开始时触发的事件,只触发一次,返回拖拽元素本身的dom节点

//拖拽开始事件,只触发一次
container.ondragstart = e => {
    console.log('start', e.target)
}

在这里插入图片描述

拖拽结束事件

表示该元素拖拽到哪个元素之上,不断触发

container.ondragover = e => {
    e.preventDefault();
    // console.log('over', e.target)
}

拖拽移入事件

类似于mouse enter,记录该元素拖拽经过哪些元素,经过只触发一次

container.ondragenter = e => {
    // console.log('enter', e.target)
}

拖拽松开事件

拖拽放手在哪个元素,table,tr,td,这些元素是不允许元素拖拽到他的上面的,因此是不会触发这个事件的。为了触发需要阻止浏览器默认事件,在ondragover中阻止

container.ondrop =e=>{
// console.log('drop', e.target)
}
container.ondragover = e => {
    e.preventDefault();
    // console.log('over', e.target)
}

实现步骤

设定移动区域划分

首先,我这边有两块可以移入的区域,第一是课程类区域,第二是课程表格区域,因此,我们使用data-drop="move"data-drop="copy",分别代表课程类区域和课程表格区域。
这里我使用的是flex布局,将两块区域分为左右两边,也就是left和right。
在这里插入图片描述

 <div class="left" data-drop="move">
                <div data-effect="copy" draggable="true"  class="color-1 item">语文</div>
                <div data-effect="copy" draggable="true" class="color-2 item">数学</div>
                <div data-effect="copy" draggable="true" class="color-3 item">英语</div>
                <div data-effect="copy" draggable="true" class="color-4 item">音乐</div>
                <div data-effect="copy" draggable="true" class="color-5 item">政治</div>
                <div data-effect="copy" draggable="true" class="color-6 item">历史</div>
            </div>
 <div class="right">
                <table border="1">
                    <colgroup>
                        <col span="6" style="background-color:#fff">
                    </colgroup>
                    <tr>
                        <th>星期一</th>
                        <th>星期二</th>
                        <th>星期三</th>
                         <th>星期四</th>
                          <th>星期五</th>
                           <th>星期六</th>
                    </tr>
                    <tr>
                        <td data-drop="copy"></td>
                        <td data-drop="copy"></td>
                        <td data-drop="copy"></td>
                          <td></td>
                        <td data-drop="copy"></td>
                        <td data-drop="copy"></td>
                    </tr>
                         <tr>
                        <td data-drop="copy"></td>
                        <td data-drop="copy"></td>
                        <td data-drop="copy"></td>
                          <td  data-drop="copy"></td>
                        <td data-drop="copy"></td>
                        <td data-drop="copy"></td>
                    </tr>
                         <tr>
                        <td data-drop="copy"></td>
                        <td data-drop="copy"></td>
                        <td data-drop="copy"></td>
                          <td  data-drop="copy"></td>
                        <td data-drop="copy"></td>
                        <td data-drop="copy"></td>
                    </tr>
                </table>
            </div>

获取拖拽节点,设定节点本身的属性

当拖拽该元素时,该节点下面会有一个‘+’的符号,这个是浏览器默认给他加上的,我们需要自定义该属性,当他拖拽到某个区域时候,就设定该属性的值为区域的值

这里我们在拖拽元素上添加一个属性data-effect="copy",通过e.target.dataset.effect获取值,并赋值给该属性

let source;

//拖拽开始事件,只触发一次
container.ondragstart = e => {
    //移动取消出现+号的效果
    e.dataTransfer.effectAllowed = e.target.dataset.effect;
    source = e.target
    console.log('start', e.target)
}

拖拽移动,区域样式变化

当我们拖拽移动的时候,对应的区域样式变化。
首先我们要先阻止浏览器的默认行为,否则不会触发ondrop事件

container.ondragover = e => {
    e.preventDefault();
    // console.log('over', e.target)
}

同时,进入某个区域的时候,样式发生变化,但是由于它移入可以会经过其他元素,所以我们要先清除之前拖拽的样式。

//清除移动的样式
function removeDropStyle() {
    document.querySelectorAll('.drop-over').forEach((node) => {
        node.classList.remove('drop-over')
    })
}

container.ondragenter = e => {
    //清除之前拖拽的样式
    removeDropStyle()
    const dropNode = getDropNode(e.target)
    if (dropNode && dropNode.dataset.drop === e.dataTransfer.effectAllowed) {
        //该节点能够接受目前拖拽节点
        e.target.classList.add('drop-over')
    }

    // console.log('enter', e.target)
}

到这里,我们就实现了拖拽该元素,并且移动到哪个区域,哪个区域的样式就会发生改变,接下来就是松开拖拽,对应区域就拥有拖拽元素。

拖拽松开,区域变化

我们要解决的问题有:
一、判断该元素是否有drop属性,如果没有,就去父元素找。
二、清除之前的元素
三、如果是move区域,就直接移除元素即可

container.ondrop = e => {
    //清除拖拽的样式
    removeDropStyle()
    console.log('drop', e.target)
    const dropNode = getDropNode(e.target)
    //该节点能够接受目前拖拽节点
    if (dropNode && dropNode.dataset.drop === e.dataTransfer.effectAllowed) {
        //两种情况,是拖拽到哪个区域,如果是copy区域
        if (dropNode.dataset.drop === 'copy') {
            //清除之前的元素
            dropNode.innerHTML = ''
            //把该元素复制一份
            const cloned = source.cloneNode(true)
            cloned.dataset.effect = 'move'
            dropNode.appendChild(cloned)
            //如果是move区域
        } else {
            console.log("1111111")
            source.remove()
        }
    }
}
//获取该元素是否有父元素
function getDropNode(node) {
    while (node) {
        if (node.dataset.drop) {
            return node
        }
        node = node.parentNode
    }
}

完整代码

index.js

//直接监控父元素,使用事件委托
const container = document.querySelector('.container');

let source;

//拖拽开始事件,只触发一次
container.ondragstart = e => {
    //移动取消出现+号的效果
    e.dataTransfer.effectAllowed = e.target.dataset.effect;
    source = e.target
    console.log('start', e.target)
}

//拖拽结束事件,表示拖拽这个元素到哪个元素之上,不断触发
container.ondragover = e => {
    e.preventDefault();
    // console.log('over', e.target)
}


//拖拽移入事件,只触发一次
container.ondragenter = e => {
    //清除之前拖拽的样式
    removeDropStyle()
    const dropNode = getDropNode(e.target)
    if (dropNode && dropNode.dataset.drop === e.dataTransfer.effectAllowed) {
        //该节点能够接受目前拖拽节点
        e.target.classList.add('drop-over')
    }

    // console.log('enter', e.target)
}

//拖拽放手在哪个元素,table,tr,td,这些元素是不允许元素拖拽到他的上面的,因此是不会触发这个事件的,触发阻止浏览器默认事件,在ondragover中阻止
container.ondrop = e => {
    //清除拖拽的样式
    removeDropStyle()
    console.log('drop', e.target)
    const dropNode = getDropNode(e.target)
    //该节点能够接受目前拖拽节点
    if (dropNode && dropNode.dataset.drop === e.dataTransfer.effectAllowed) {
        //两种情况,是拖拽到哪个区域,如果是copy区域
        if (dropNode.dataset.drop === 'copy') {
            //清除之前的元素
            dropNode.innerHTML = ''
            //把该元素复制一份
            const cloned = source.cloneNode(true)
            cloned.dataset.effect = 'move'
            dropNode.appendChild(cloned)
            //如果是move区域
        } else {
            console.log("1111111")
            source.remove()
        }
    }
}

//获取该元素是否有父元素
function getDropNode(node) {
    while (node) {
        if (node.dataset.drop) {
            return node
        }
        node = node.parentNode
    }
}

//清除移动的样式
function removeDropStyle() {
    document.querySelectorAll('.drop-over').forEach((node) => {
        node.classList.remove('drop-over')
    })
}

index.css

body {
    margin: 0;
    padding: 0;
}

h1 {
    width: 100%;
    text-align: center;
}

.container {
    width: 100%;
    height: 800px;
    display: flex;
    flex-direction: row;

}

.left {
    width: 5%;
    background: #f3f4f5;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.item {
    width: 100%;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 70px;
    font-size: 20px;
    font-weight: 500;
    margin-bottom: 20px;
    color: #fff;
}

.right {
    margin-left: 40px;
    width: 95%;
    background: #f3f4f5;
}

.color-1 {
    background: red;
}

.color-2 {
    background: rgb(18, 49, 189);
}

.color-3 {
    background: rgb(22, 153, 33);
}

.color-4 {
    background: rgb(150, 136, 12);
}

.color-5 {
    background: rgb(110, 9, 114);
}

.color-6 {
    background: rgb(192, 118, 22);
}

td {
    width: 90px;
    height: 70px;
    ;
}

.drop-over {
    background: rgba(212, 13, 56, 0.067);
}

index.html

<!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>
        <link href="./index.css" rel="stylesheet"></link>
    </head>
    <body>
        <h1>课程表</h1>
        <div class="container">
            <div class="left" data-drop="move">
                <div data-effect="copy" draggable="true"  class="color-1 item">语文</div>
                <div data-effect="copy" draggable="true" class="color-2 item">数学</div>
                <div data-effect="copy" draggable="true" class="color-3 item">英语</div>
                <div data-effect="copy" draggable="true" class="color-4 item">音乐</div>
                <div data-effect="copy" draggable="true" class="color-5 item">政治</div>
                <div data-effect="copy" draggable="true" class="color-6 item">历史</div>
            </div>
            <div class="right">
                <table border="1">
                    <colgroup>
                        <col span="6" style="background-color:#fff">
                    </colgroup>
                    <tr>
                        <th>星期一</th>
                        <th>星期二</th>
                        <th>星期三</th>
                         <th>星期四</th>
                          <th>星期五</th>
                           <th>星期六</th>
                    </tr>
                    <tr>
                        <td data-drop="copy"></td>
                        <td data-drop="copy"></td>
                        <td data-drop="copy"></td>
                          <td></td>
                        <td data-drop="copy"></td>
                        <td data-drop="copy"></td>
                    </tr>
                         <tr>
                        <td data-drop="copy"></td>
                        <td data-drop="copy"></td>
                        <td data-drop="copy"></td>
                          <td  data-drop="copy"></td>
                        <td data-drop="copy"></td>
                        <td data-drop="copy"></td>
                    </tr>
                         <tr>
                        <td data-drop="copy"></td>
                        <td data-drop="copy"></td>
                        <td data-drop="copy"></td>
                          <td  data-drop="copy"></td>
                        <td data-drop="copy"></td>
                        <td data-drop="copy"></td>
                    </tr>
                </table>
            </div>
        </div>
        <script src="./index.js"></script>
    </body>
</html>

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

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

相关文章

轻量化Verilog开发环境搭建

轻量化Verilog学习环境搭建 本文记录基于vscode、iverilog搭建轻量化Verilog学习环境的方法。 ref: VSCode Verilog工具链、linux下搭建轻量易用的verilog仿真环境 环境搭建 &#xff08;1&#xff09;安装iverilog&#xff0c;这是一个轻量化的开源verilog编译器&#xff0…

4月更新 | Visual Studio Code Python

我们很高兴地宣布2023年4月版 Visual Studio Code 的 Python 和 Jupyter 扩展现已推出&#xff01; 此版本包括以下改进&#xff1a; Data Wrangler 可供 Visual Studio Code Insiders 使用移动符号重构Create Environment 按钮嵌入依赖文件扩展作者的环境 APIPython 环境的内…

Foxit PDF Reader及Editor任意代码执行漏洞复现(CVE-2023-27363)

0x01 产品简介 Foxit PDF Reader是一套用来阅读PDF格式文件的软件&#xff0c;由福建福昕软件所研发&#xff0c;主要运行在Windows操作系统上。 0x02 漏洞概述 Foxit PDF Reader及Editor中存在任意代码执行漏洞&#xff0c;由于Foxit PDF Reader/Editor未验证exportXFAData方…

【C++】3. 类和对象 - 类的六大默认成员函数

专栏导读 &#x1f341;作者简介&#xff1a;余悸&#xff0c;在读本科生一枚&#xff0c;致力于 C方向学习。 &#x1f341;收录于 C专栏&#xff0c;本专栏主要内容为 C初阶、 C 进阶、STL 详解等&#xff0c;持续更新中&#xff01; &#x1f341;相关专栏推荐&#xff1a; …

定薪17K*15,阿里测试岗上岸经验分享.....

先简单介绍一下我自己吧&#xff0c;等会大家以为我是什么学历狂人&#xff0c;技术大牛&#xff0c;我毕业于广东一个普通本科院校&#xff0c;绝对不是什么双一流大学&#xff0c;大家不要有距离感&#xff0c;这也是我为什么来分享的原因&#xff0c;因为我觉得我这段经验还…

Agisoft Metashape 空三导入Photomod

Agisoft Metashape 空三导入Photomod 文章目录 Agisoft Metashape 空三导入Photomod前言一、Metashape空三成果导出1.1导出PAT-B空三格式1.2. 导出相机文件二、Photomod空三成果导入2.1导入PAT-B空三格式2.2导入相机文件前言 本文讲解将Agisoft Metashape的空三成果导入Photom…

uniapp - 微信小程序接入腾讯视频播放器功能插件,uniapp开发微信小程序端调用引入并使用腾讯视频播放组件完整全流程(详细示例源码,一键复制开箱即用)

效果图 在uniapp 微信小程序项目中,集成腾讯视频功能插件,实现播放腾讯视频效果,附带详细示例源码及注释, 你可以跟着步骤一步步来,保证几分钟就能快速在uniapp小程序项目中植入腾讯视频功能! 一、开通插件 首先使用腾讯视频的话

【数据结构】链表的增删改查| 组件化封装

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;专栏汇总&#xff1a;全部文章专栏汇总 &#x1f525; 给大…

BSN-DDC基础网络详解(十一):官方门户OpenAPI说明及开发资料汇总

01 官方门户OpenAPI说明 官方门户OpenAPI是BSN联盟面向算力中心方和平台方开放的一套官方门户业务管理服务接口。“业务开通”和“资金账户充值/提现”操作&#xff0c;需通过官方门户手工执行&#xff0c;官方门户内的其它功能&#xff0c;都建议算力中心方和平台方按照官方…

Mongo集合操作

2、创建切换数据库 2.1 默认数据库 mongo数据库和其他类型的数据库一样&#xff0c;可以创建数据库&#xff0c;且可以创建多个数据库。 mongo数据库默认会有四个数据库&#xff0c;分别是 admin&#xff1a;主要存储MongoDB的用户、角色等信息 config&#xff1a;主要存储…

数据泄露、数据爬取......金融机构要如何保护催收场景下的数据安全?

金融企业的贷后催收是指向借款人发送催收通知和采取其他措施&#xff0c;以确保借款人按时还款并追回逾期贷款的过程。这通常包括电话催收、信函催收、上门访问等方式。贷后催收通常由金融机构内部的专业团队或第三方专业催收公司承担。 由于催收业务会涉及到很多个人信息&…

家政服务预约小程序开发 解放双手享受洁净生活

在外工作忙了了一天回到家还有做不完的家务&#xff0c;很多时候家庭主妇总是受不了这样的生活二崩溃&#xff0c;随着生活水平的提高&#xff0c;上门家政预约类软件层出不穷&#xff0c;让万千家庭足不出户就可在线预约家政服务&#xff0c;在家享受专业的保洁、维修、安装等…

鸿蒙Hi3861学习十四-Huawei LiteOS-M(STA模式)

一、简介 AP&#xff08;Access Point&#xff09;无线接入点 AP是无线接入点&#xff0c;是一个无线网络的创建者&#xff0c;是网络的中心节点。一般家庭或办公室使用的无线路由器就是一个AP。 STA&#xff08;Station&#xff09;站点 STA也可以理解为终端的意思&#xff…

进行性能压力测试的原因、目的和好处

性能压力测试是指在模拟高负载、高并发情况下对软件系统进行测试&#xff0c;以衡量系统在实际使用过程中的性能表现。这些测试可以为生产环境中的应用程序提供关键数据&#xff0c;并帮助开发人员从根本上了解系统的实际性能。在本文中&#xff0c;我们将探讨进行性能压力测试…

微信视频号视频可以下载吗?视频下载器安装使用教程

简介 最近小伙伴推荐了一款视频下载神器&#xff0c;它可以批量下载微信视频号中的视频到本地上&#xff0c;我试了一下非常简单方便&#xff0c;而且还支持预览等操作&#xff0c;今天分享给大家 软件下载 ➤ 微信视频号下载器下载 ⇲ 安装使用教程 安装 我们下载好对应…

Centos7安装配置MySQL 8.0.20

安装配置MySQL 8.0.20 步骤一&#xff1a;安装MySQL 8.0.20 使用wget命令从mysql官网下载MySQL8.0.20安装包&#xff1a; wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.20-linux-glibc2.12-x86_64.tar.xz解压安装包&#xff1a; tar -Jxvf mysql-8.0.20-…

QT 操作SQL

目录 一、QT SQL简介 (一&#xff09;、QT SQL对数据库支持 1、驱动层 2、SQL API层 3、用户接口层 &#xff08;二&#xff09;SQLite数据库初识 1、第一步&#xff1a;在项目管理文件&#xff08;.pro&#xff09;中增加数据库模块​编辑 2、第二步&#xff1a;查看…

用讯飞星火大模型1分钟写一个精美的PPT

文章目录 前言SparkDesk讯飞星火认知大模型简介利用讯飞星火写一个转正述职ppt1.告诉讯飞星火我想写一篇转正述职ppt2.利用MindShow一键生成ppt 申请体验写在最后 前言 随着ChatGPT迅速走红,国内各大企业纷纷发力认知大模型领域。经过一段时间的酝酿,讯飞“星火认知大模型”于…

家门口可以参加公益小天使活动啦

“我的布娃娃可以换你的书吗&#xff1f;” “发现有人晕倒&#xff0c;第1步要确认环境安全。” 这是5月14日上午&#xff0c;在武昌区水果湖街道滨湖社区&#xff0c;闲置互换应急科普活动上发生的对话 该活动由水果湖街道滨湖社区和武汉公益小天使联合发起。5月初&#x…

出现找不到msvcp140.dll无法继续执行代码要怎么解决?

出现找不到msvcp140.dll无法继续执行代码要怎么解决&#xff1f;当你尝试在Windows系统上运行某些程序或游戏时&#xff0c;可能会遇到“找不到msvcp140.dll无法继续执行代码”的错误提示。这个错误通常表示你的系统缺少了msvcp140.dll文件&#xff0c;而这个文件是Visual C Re…