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

前言

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>

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

区间合并(算法)

目录 题目代码实现注意点 题目 给定 n n n 个区间 [ l i , r i ] [l_i, r_i] [li​,ri​]&#xff0c;要求合并所有有交集的区间。 注意如果在端点处相交&#xff0c;也算有交集。 输出合并完成后的区间个数。 例如&#xff1a; [ 1 , 3 ] [1,3] [1,3] 和 [ 2 , 6 ] [2,…

Maven POM和Maven构建配置文件操作笔记

目录 我到现在还是没有太搞懂Maven的作用&#xff0c;我只是有一个模糊的概念就是它可以添加很多的依赖&#xff0c;这样会使项目搭建起来更加方便&#xff0c;你可以谈谈你的看法吗&#xff1f; Maven POM 父&#xff08;Super&#xff09;POM POM 标签大全详解 Maven 构建…

DSP:数字信号处理的原理及应用

什么是DSP&#xff1f;DSP一般有两种解释&#xff1a; 1、Digital Signal Processing&#xff0c;数字信号处理技术&#xff0c;简称DSP。是一门涉及许多学科而又广泛应用于许多领域的新兴学科。数字信号处理是围绕着数字信号处理的理论、实现和应用等几个方面发展起来的。数字…

如何用u盘重装系统win7

​如今的U盘重装win7系统是比较常见的重装win7系统的方法&#xff0c;适用性比较高&#xff0c;操作也十分的简单。有的小伙伴想给自己的电脑重装win7&#xff0c;那么我们用u盘重装系统怎么安装win7?现在小编就来教大家如何用u盘重装系统教程。 工具/原料&#xff1a; 系统…

git commit 设置 eslint + pretter 格式化校验

系统版本 node 版本: v14.17.5 npm 版本: 6.14.14 vue-cli 版本: vue/cli 4.5.19 目录 系统版本 1. 新建一个 vue2.X 空项目 2. 安装插件 eslint ,并初始化 eslint 配置,根目录生成 .eslintrc 配置文件 3. 测试 eslint 配置 4. 安装 husky、lint-staged 5. 在package.j…

使用svg在元素直接绘制连线箭头

注意&#xff1a;svg的图形绘制的点位置坐标是基于画布的位置坐标&#xff0c;相当于从左上角的点为起点。 先来个简单示例&#xff1a; 在点与点之间绘制连线箭头 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8">…

ChatGPT学习-如何向ChatGPT提问

​ 最近在学习chatGPT,怎么样的提问是一个好的提问。通过网上找资料肯定不是最好的方法&#xff0c;我想起一句话&#xff0c;“不识庐山真面目&#xff0c;只缘身在此山中”。最好的老师就是chatGPT&#xff01; 下面先展示下提问成果&#xff0c;我通过xmind生成了思维导图 一…

科思转债上市价格预测

科思转债 基本信息 转债名称&#xff1a;科思转债&#xff0c;评级&#xff1a;AA-&#xff0c;发行规模&#xff1a;7.249178亿元。 正股名称&#xff1a;科思股份&#xff0c;今日收盘价&#xff1a;67.1元&#xff0c;转股价格&#xff1a;53.03元。 当前转股价值 转债面值…

电脑断电文件丢失如何找回?给你支几招!

电脑断电文件丢失如何找回&#xff1f;我好不容易熬夜加班做的活动方案&#xff0c;正当将U盘文件转移到笔记本电脑的时候&#xff0c;没有注意笔记本的电量&#xff0c;在转移数据的过程中突然断电了。我的电脑一下子就“熄”了&#xff0c;方案都没来得及保存。这真是一个悲剧…

MySQL主从复制与读写分离

目录 一、mysql主从复制原理1.1 mysql的复制类型1.2 mysql主从复制的工作原理 二、mysql读写分离原理2.1 读写分离的意义2.2 常见的两种mysql读写分离2.2.1.基于程序代码内部实现2.2.2.基于中间代理层实现2.2.3 amoeba 2.3 mysql读写分离原理 三、mysql数据库四种同步方式3.1 异…

MySQL视图详解

我写本文主要目的&#xff0c;是在网上看见了 所以&#xff0c;文本主要探讨的问题如下&#xff0c;验证结果在最后面 一、修改视图&#xff0c;基表会跟着改吗&#xff1f;答案&#xff1a;会改变 二、修改基表&#xff0c;视图会变化吗&#xff1f;答案&#xff1a;会改变 …

Nevron Open Vision for .NET 2022.3 Crack

Nevron Open Vision for .NET 适用于 Blazor、WPF、WinForms 和 Xamarin.Mac 的领先用户界面组件 Nevron Open Vision for .NET 是一套高级 UI 组件&#xff0c;可帮助您从单个代码库开发功能丰富的 Web &#xff08;Blazor WebAssembly&#xff09; 和桌面 &#xff08;WinFor…

手搓GPT系列之 - 通过理解LSTM的反向传播过程,理解LSTM解决梯度消失的原理 - 逐条解释LSTM创始论文全部推导公式,配超多图帮助理解(上篇)

1. 前言 说起RNN和LSTM&#xff0c;就绕不过Sepp Hochreiter 1997年的开山大作 Long Short-term Memory。奈何这篇文章写的实在是太劝退&#xff0c;整篇论文就2张图&#xff0c;网上很多介绍LSTM的文章都对这个模型反向传播的部分避重就轻&#xff0c;更少见&#xff08;反正…

照片尺寸怎么调整大小?三个方法,高效、快捷、安全!

照片尺寸怎么调整大小&#xff1f;照片是我们在日常生活和办公中经常会使用的文件类型之一。在制作各种文件、讲义、PPT、视频等内容时&#xff0c;图片都会成为重要的一部分。不同的图片格式和大小各有特点&#xff0c;有些图片虽然比较大但画质清晰&#xff0c;有些则方便传输…

网络安全公司Dragos披露网络安全事件

工业网络安全公司 Dragos 披露了它所称的“网络安全事件”&#xff0c;此前一个已知的网络犯罪团伙试图突破其防御并渗透到内部网络以加密设备。 虽然 Dragos 表示威胁行为者没有破坏其网络或网络安全平台&#xff0c;但他们可以访问公司的 SharePoint 云服务和合同管理系统。…

Windows系统下Chromedriver.exe安装及配置

Windows系统下Chromedriver.exe安装及配置 在利用selenium工具进行Web自动化测试时&#xff0c;必须先要安装浏览器驱动&#xff0c;通常比较常用的是谷歌浏览器和火狐浏览器。 一、浏览器驱动下载地址 1.浏览器驱动官网&#xff1a;http://chromedriver.storage.googleapis…

【Midjourney】Midjourney 的 Prompt 指令类型 ( 画风指令 | 人物细节指令 | 灯光镜头指令 | 艺术家风格指令 )

文章目录 一、Midjourney 的 Prompt 详细指令规则二、Midjourney 的画风指令关键词1、超现实主义2、注重细节描写3、Artstation 画风4、数字绘画风格5、漫画风格6、线条艺术 三、Midjourney 的人物细节描写关键词1、面部特征描写2、身体描写3、生成示例 14、生成示例 2 四、Mid…

(MIT6.045)自动机、可计算性和复杂性-DFA和NFA

毕业论文写完了。找点事干干。 佛系更新。 这是一门讲述 什么是计算&#xff1f;什么能被计算&#xff1f;怎么高效计算&#xff1f; 的哲学、数学和工程问题的课程。 主要包括&#xff1a; 有限状态机&#xff08;Finite Avtomata&#xff09;&#xff1a;简单的模型。 可…

在Linux中进行Jenkins部署(maven-3.9.1+jdk11)

Jenkins部署在公网IP为x.x.x.x的服务器上 maven-3.9.1要安装在jdk11环境中 环境准备 第一步&#xff0c;下载jdk-11.0.19_linux-x64_bin.tar.gz安装包。 登录地址&#xff1a;Java Downloads | Oracle 下载jdk-11.0.19_linux-x64_bin.tar.gz安装包&#xff0c;然后使用Win…

C++11

目录 一、C11的诞生 二、initializer_list 1.统一的初始化方案 2.initializer_list 三、五个关键字 1.auto 2.decltype 3.nullptr 4.final 5.override 四、STL的新容器 1.array 2.forward_list 3.unordered_map与unordered_set 4.新增成员函数 五、右值引用和移…