HTML5拖拽API学习 托拽排序和可托拽课程表
文章目录
- 前言
- 拖拽API核心概念
- 拖拽式使用流程
- 例子
- 注意事项
- 综合例子🌰 可拖拽课程表
- 拖拽排序
前言
前端拖拽功能让网页元素可以通过鼠标或触摸操作移动。HTML5 提供了标准的拖拽API,简化了拖放操作的实现。以下是拖拽API的基本使用指南:
拖拽API核心概念
- draggable属性:设置元素的
draggable="true"
属性,允许用户拖动该元素。
<div draggable="true">可拖动元素</div>
- dragstart事件:拖动开始时触发,可以设置拖动数据。
const draggableElement = document.querySelector('div');draggableElement.addEventListener('dragstart', (event) => {event.dataTransfer.setData('text/plain', '拖动数据');});
- dragover事件:拖动元素在目标区域上方时触发,需要调用
event.preventDefault()
以允许放置。
const dropZone = document.querySelector('#dropZone');dropZone.addEventListener('dragover', (event) => {event.preventDefault(); // 允许放置});
- drop事件:拖动元素放置到目标区域时触发,可以获取拖动数据。
dropZone.addEventListener('drop', (event) => {event.preventDefault();const data = event.dataTransfer.getData('text/plain');console.log('放置的数据:', data);});
- dragend事件:拖动操作结束时触发,用于清理拖动状态或重置样式。
draggableElement.addEventListener('dragend', () => {draggableElement.style.backgroundColor = ''; // 重置样式});
拖拽式使用流程
- 设置可拖拽元素:在HTML中为元素添加
draggable="true"
属性。 - 处理拖拽开始事件:在
dragstart
事件中设置拖拽数据。 - 设置目标区域:通过
dragover
事件处理,允许放置操作。 - 处理放置事件:在
drop
事件中获取数据并处理放置逻辑。 - 清理拖拽操作:在
dragend
事件中清理元素样式或状态。
例子
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>拖拽示例</title><style>#dragElement {width: 100px; height: 100px; background-color: skyblue; cursor: move; text-align: center; line-height: 100px;}#dropZone {width: 300px; height: 300px; border: 2px dashed #aaa; margin-top: 50px; text-align: center; line-height: 300px; color: #888;}</style></head><body><div id="dragElement" draggable="true">拖我</div><div id="dropZone">在这里放置</div><script>const dragElement = document.getElementById('dragElement');const dropZone = document.getElementById('dropZone');dragElement.addEventListener('dragstart', (event) => {console.log('拖拽开始');event.dataTransfer.setData('text/plain', 'Hello, 拖拽');event.target.style.backgroundColor = 'orange';});dropZone.addEventListener('dragover', (event) => {console.log('拖拽进入');event.preventDefault();});dropZone.addEventListener('drop', (event) => {console.log('拖拽放下');event.preventDefault();const data = event.dataTransfer.getData('text/plain');dropZone.innerHTML = `放置了:${data}`;});dragElement.addEventListener('dragend', (event) => {console.log('拖拽结束');event.target.style.backgroundColor = 'skyblue';});</script></body></html>
注意事项
- 兼容性:大多数现代浏览器支持HTML5拖拽API,但老旧浏览器如IE8及以下不支持。
- 样式:可以通过设置样式增强用户体验,如改变光标或透明度。
- 文件拖放:HTML5还支持拖拽文件到浏览器特定区域,可以通过
event.dataTransfer.files
获取文件数据。
综合例子🌰 可拖拽课程表
<!DOCTYPE html><html lang="zh-CN"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>可拖拽课程表</title><style>body {margin: 0;padding: 20px;}.schedule-container {display: flex;gap: 20px;max-width: 1400px;margin: 0 auto;}.schedule-table {flex: 1;display: grid;grid-template-columns: 100px repeat(7, 1fr);gap: 2px;background-color: #fff;border: 1px solid #ddd;height: fit-content;}.time-column {background-color: #f8f9fa;padding: 10px;text-align: center;font-weight: bold;}.header-row {background-color: #f8f9fa;padding: 10px;text-align: center;font-weight: bold;}.course-list {width: 250px;padding: 15px;border: 1px solid #ddd;background-color: #f8f9fa;border-radius: 8px;height: fit-content;}.course-list h3 {margin-top: 0;margin-bottom: 15px;color: #333;}#available-courses {display: flex;flex-direction: column;gap: 10px;}</style></head><body><div class="schedule-container"><div class="schedule-table"><!-- 表头 --><div class="header-row">时间</div><div class="header-row">周一</div><div class="header-row">周二</div><div class="header-row">周三</div><div class="header-row">周四</div><div class="header-row">周五</div><div class="header-row">周六</div><div class="header-row">周日</div></div><!-- 课程列表 --><div class="course-list"><h3>可选课程</h3><div id="available-courses"><!-- 这里会通过JavaScript动态生成可拖拽的课程 --></div></div></div><script src="tuozuaiApi.js"></script></body></html>
//tuozhaiApi.js
// 课程表拖拽功能实现const DragSchedule = {init() {this.scheduleTable = document.querySelector('.schedule-table');this.availableCourses = document.getElementById('available-courses');this.createTimeSlots();this.createSampleCourses();this.cells = document.querySelectorAll('.schedule-cell');this.courses = document.querySelectorAll('.course-item');this.bindEvents();this.loadScheduleState();},createTimeSlots() {// 创建时间段(第一节课从8:00开始)const times = ['8:00-8:45', '8:55-9:40', '9:50-10:35', '10:45-11:30','13:30-14:15', '14:25-15:10', '15:20-16:05', '16:15-17:00'];times.forEach((time, index) => {// 添加时间列const timeCell = document.createElement('div');timeCell.className = 'time-column';timeCell.textContent = `第${index + 1}节\n${time}`;this.scheduleTable.appendChild(timeCell);// 添加每一天的课程格子for (let day = 0; day < 7; day++) {const cell = document.createElement('div');cell.className = 'schedule-cell';cell.setAttribute('data-time', index);cell.setAttribute('data-day', day);this.scheduleTable.appendChild(cell);}});},createSampleCourses() {const sampleCourses = [{ id: 1, name: '高等数学', color: '#ff9999' },{ id: 2, name: '大学英语', color: '#99ff99' },{ id: 3, name: '程序设计', color: '#9999ff' },{ id: 4, name: '物理实验', color: '#ffff99' },{ id: 5, name: '体育课', color: '#ff99ff' }];sampleCourses.forEach(course => {const courseElement = document.createElement('div');courseElement.className = 'course-item';courseElement.setAttribute('data-course-id', course.id);courseElement.setAttribute('draggable', true); // 添加draggable属性courseElement.textContent = course.name;courseElement.style.backgroundColor = course.color;this.availableCourses.appendChild(courseElement);});},bindEvents() {// 为每个课程添加拖拽事件this.courses.forEach(course => {course.ondragstart = (e) => {e.target.classList.add('dragging');e.dataTransfer.setData('text/plain', e.target.getAttribute('data-course-id'));};course.ondragend = (e) => {e.target.classList.remove('dragging');};});// 为每个单元格添加放置事件this.cells.forEach(cell => {cell.ondragover = (e) => {e.preventDefault();e.currentTarget.classList.add('drag-over');};cell.ondragleave = (e) => {e.currentTarget.classList.remove('drag-over');};cell.ondrop = this.handleDrop.bind(this);});},saveScheduleState() {const scheduleState = {};this.cells.forEach((cell, index) => {const courseElement = cell.querySelector('.course-item');if (courseElement) {scheduleState[index] = courseElement.getAttribute('data-course-id');}});localStorage.setItem('scheduleState', JSON.stringify(scheduleState));},loadScheduleState() {const savedState = localStorage.getItem('scheduleState');if (savedState) {const scheduleState = JSON.parse(savedState);Object.entries(scheduleState).forEach(([cellIndex, courseId]) => {const cell = this.cells[cellIndex];const courseElement = document.querySelector(`[data-course-id="${courseId}"]`);if (cell && courseElement) {const newCourse = courseElement.cloneNode(true);newCourse.setAttribute('draggable', true);newCourse.ondragstart = (e) => {e.target.classList.add('dragging');e.dataTransfer.setData('text/plain', e.target.getAttribute('data-course-id'));};newCourse.ondragend = (e) => {e.target.classList.remove('dragging');};cell.appendChild(newCourse);}});}},handleDrop(e) {e.preventDefault();const cell = e.currentTarget;cell.classList.remove('drag-over');const courseId = e.dataTransfer.getData('text/plain');const courseElement = document.querySelector(`[data-course-id="${courseId}"]`);// 如果课程已经在其他单元格中,创建一个副本const newCourse = courseElement.cloneNode(true);newCourse.setAttribute('draggable', true);newCourse.ondragstart = (e) => {e.target.classList.add('dragging');e.dataTransfer.setData('text/plain', e.target.getAttribute('data-course-id'));};newCourse.ondragend = (e) => {e.target.classList.remove('dragging');};// 检查单元格是否已有课程if (cell.querySelector('.course-item')) {const existingCourse = cell.querySelector('.course-item');cell.removeChild(existingCourse);}cell.appendChild(newCourse);// 保存课程表状态this.saveScheduleState();}};// 添加更多样式const style = document.createElement('style');style.textContent = `.schedule-cell {min-height: 80px;border: 1px solid #ddd;padding: 8px;background-color: #fff;}.course-item {padding: 8px;margin: 4px;border-radius: 4px;cursor: move;color: #fff;text-shadow: 1px 1px 1px rgba(0,0,0,0.2);box-shadow: 2px 2px 4px rgba(0,0,0,0.1);}.dragging {opacity: 0.5;}.drag-over {background-color: #e9ecef;}.time-column {white-space: pre-line;font-size: 12px;}`;document.head.appendChild(style);// 初始化拖拽功能document.addEventListener('DOMContentLoaded', () => {DragSchedule.init();});
拖拽排序
<!DOCTYPE html><html lang="zh"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>拖拽排序示例</title><style>.sortable-list {width: 300px;margin: 20px auto;padding: 0;}.sortable-item {list-style: none;background-color: #f0f0f0;margin: 5px 0;padding: 10px 15px;border-radius: 4px;cursor: move;transition: background-color 0.3s;}.sortable-item.dragging {opacity: 0.5;background-color: #e0e0e0;}.sortable-item:hover {background-color: #e8e8e8;}</style></head><body><ul class="sortable-list"><li class="sortable-item" draggable="true">项目 1</li><li class="sortable-item" draggable="true">项目 2</li><li class="sortable-item" draggable="true">项目 3</li><li class="sortable-item" draggable="true">项目 4</li><li class="sortable-item" draggable="true">项目 5</li></ul><script>const sortableList = document.querySelector('.sortable-list');let draggingItem = null;// 为每个列表项添加拖拽事件监听器document.querySelectorAll('.sortable-item').forEach(item => {item.addEventListener('dragstart', handleDragStart);item.addEventListener('dragend', handleDragEnd);item.addEventListener('dragover', handleDragOver);item.addEventListener('drop', handleDrop);});function handleDragStart(e) {draggingItem = this;this.classList.add('dragging');// 设置拖拽效果e.dataTransfer.effectAllowed = 'move';e.dataTransfer.setData('text/plain', ''); // 必须调用setData才能在Firefox中触发drop}function handleDragEnd(e) {this.classList.remove('dragging');draggingItem = null;}function handleDragOver(e) {e.preventDefault();if (this === draggingItem) return;// 获取鼠标位置相对于当前项的位置const rect = this.getBoundingClientRect();const midY = rect.top + rect.height / 2;if (e.clientY < midY) {// 如果鼠标在元素上半部分,就插入到当前元素之前sortableList.insertBefore(draggingItem, this);} else {// 如果鼠标在元素下半部分,就插入到当前元素之后sortableList.insertBefore(draggingItem, this.nextSibling);}}function handleDrop(e) {e.preventDefault();}</script></body></html>
相关文章:
HTML5拖拽API学习 托拽排序和可托拽课程表
文章目录 前言拖拽API核心概念拖拽式使用流程例子注意事项综合例子🌰 可拖拽课程表拖拽排序 前言 前端拖拽功能让网页元素可以通过鼠标或触摸操作移动。HTML5 提供了标准的拖拽API,简化了拖放操作的实现。以下是拖拽API的基本使用指南: 拖拽…...
内容补充页(相关公式解释)
from 学习日记_20241117_聚类方法(高斯混合模型) 学习日记_20241117_聚类方法(高斯混合模型) 公式 P ( Z k ) π k P(Zk) \pi_k P(Zk)πk 在高斯混合模型 (GMM) 中,公式 P ( Z k ) π k P(Zk) \pi_k P(Zk…...
vue中动态渲染静态图片资源
不报错且f12查看元素的时候,显示的src说明已经渲染到html的src上,但是就是不显示在页面上 原因 在vue上,动态渲染静态图片资源(比如从assets文件夹加载的图片)需要注意打包工具对静态资源的解析方式 由于vue2的脚手…...
管伊佳ERP,原名华夏ERP,一个简约易上手的国产ERP系统
JSH_ERP(管伊佳ERP)是一款开源、模块化的企业资源计划系统,旨在为中小企业提供高效的管理工具。它基于SpringBoot框架和SaaS模式,支持进销存、财务、生产等业务模块,包括零售、采购、销售、仓库和报表管理。 核心特点…...
学习虚幻C++开发日志——委托(持续更新中)
委托 官方文档:Delegates and Lamba Functions in Unreal Engine | 虚幻引擎 5.5 文档 | Epic Developer Community | Epic Developer Community 简单地说,委托就像是一个“函数指针”,但它更加安全和灵活。它允许程序在运行时动态地调用不…...
开窗函数 - first_value/last_value
1、开窗函数是什么? 开窗函数用于为行定义一个窗口(这里的窗口是指运算将要操作的行的集合),它对一组值进行操作,不需要使用 GROUP BY 子句对数据进行分组,能够在同一行中同时返回基础行的列和聚合列。 2、…...
「一」HarmonyOS端云一体化概要
关于作者 白晓明 宁夏图尔科技有限公司董事长兼CEO、坚果派联合创始人 华为HDE、润和软件HiHope社区专家、鸿蒙KOL、仓颉KOL 华为开发者学堂/51CTO学堂/CSDN学堂认证讲师 开放原子开源基金会2023开源贡献之星 「目录」 「一」HarmonyOS端云一体化概要 「二」体验HarmonyOS端云一…...
nodejs21: 快速构建自定义设计样式Tailwind CSS
Tailwind CSS 是一个功能强大的低级 CSS 框架,只需书写 HTML 代码,无需书写 CSS,即可快速构建美观的网站。 1. 安装 Tailwind CSS React 项目中安装 Tailwind CSS: 1.1 安装 Tailwind CSS 和相关依赖 安装 Tailwind CSS: npm…...
从JSON数据提取嵌套字段并转换为独立列的简洁方法
从JSON数据提取嵌套字段并转换为独立列的简洁方法 在数据处理和数据分析的日常工作中,我们经常遇到复杂的嵌套数据结构,特别是嵌入在JSON字段中的数据。这些数据往往需要解析并展开成独立的列,以便后续分析和建模。本文将详细介绍如何在Pyth…...
湘潭大学软件工程算法设计与分析考试复习笔记(四)
回顾 湘潭大学软件工程算法设计与分析考试复习笔记(一)湘潭大学软件工程算法设计与分析考试复习笔记(二)湘潭大学软件工程算法设计与分析考试复习笔记(三) 前言 现在是晚上十一点,我平时是十…...
特征交叉-DeepCross Network学习
一 tensorflow官方实现 tensorflow的官方实现已经是V2版本 class Cross(tf.keras.layers.Layer):"""Cross Layer in Deep & Cross Network to learn explicit feature interactions.Args:projection_dim: int,低秩矩阵的维度,应该小…...
stm32cubemx+VSCODE+GCC+makefile 开发环境搭建
title: stm32cubemxVSCODEGCCmakefile 开发环境搭建 tags: FreertosHalstm32cubeMx 文章目录 内容往期内容导航第一步准备环境vscode 插件插件配置点灯 内容 往期内容导航 第一步准备环境 STM32CubeMXVSCODEMinGWOpenOcdarm-none-eabi-gcc 然后把上面下载的软件 3 4 5 bin 文…...
Go语言中的Defer机制详解与示例
在Go语言中,defer是一个关键字,用于确保资源的清理和释放,特别是在函数中创建的资源。defer语句会将其后的函数调用推迟到包含它的函数即将返回时执行。这使得defer成为处理文件关闭、数据库连接释放、解锁等资源清理操作的理想选择。 Defer…...
H.265流媒体播放器EasyPlayer.js H5流媒体播放器如何验证视频播放是否走硬解
随着技术的不断进步和5G网络的推广,中国流媒体播放器行业市场规模以及未来发展趋势都将持续保持稳定的增长,并将在未来几年迎来新的发展机遇。流媒体播放器将继续作为连接内容创作者和观众的重要桥梁,推动数字媒体产业的创新和发展。 EasyPla…...
ms-hot目录
1. ms-hot1...
vulfocus在线靶场:骑士cms_cve_2020_35339:latest 速通手册
目录 一、启动环境,访问页面,ip:端口号/index.php?madmin,进入后台管理页面,账号密码都是adminadmin 二、进入之后,根据图片所示,地址后追加一下代码,保存修改 三、新开标签页访问:①ip:端…...
AI Large Language Model
AI 的 Large Language model LLM , 大语言模型: 是AI的模型,专门设计用来处理自然语言相关任务。它们通过深度学习和庞大的训练数据集,在理解和生成自然语言文本方面表现出色。常见的 LLM 包括 OpenAI 的 GPT 系列、Google 的 PaLM 和 Meta…...
React Native的`react-native-reanimated`库中的`useAnimatedStyle`钩子来创建一个动画样式
React Native的react-native-reanimated库中的useAnimatedStyle钩子来创建一个动画样式,用于一个滑动视图的每个项目(SliderItem)。useAnimatedStyle钩子允许你根据动画值(在这个例子中是scrollX)来动态地设置组件的样…...
FastJson反序列化漏洞(CVE-2017-18349)
漏洞原理 原理就不多说了,可以去看我这篇文章,已经写得很详细了。 Java安全—log4j日志&FastJson序列化&JNDI注入-CSDN博客 影响版本 FastJson<1.2.24 复现过程 这里我是用vulfocus.cn这个漏洞平台去复现的,比较方便&#x…...
【优选算法篇】分治乾坤,万物归一:在重组中窥见无声的秩序
文章目录 分治专题(二):归并排序的核心思想与进阶应用前言、第二章:归并排序的应用与延展2.1 归并排序(medium)解法(归并排序)C 代码实现易错点提示时间复杂度和空间复杂度 2.2 数组…...
C++:探索AVL树旋转的奥秘
文章目录 前言 AVL树为什么要旋转?一、插入一个值的大概过程1. 插入一个值的大致过程2. 平衡因子更新原则3. 旋转处理的目的 二、左单旋1. 左单旋旋转方式总处理图2. 左单旋具体会遇到的情况3. 左单旋代码总结 三、右单旋1. 右单旋旋转方式总处理图2. 右单旋具体会遇…...
2. Django中的URL调度器 (自定义路径转换器)
在 Django 中,URL 路由通常使用路径转换器(path converters)来匹配和捕获 URL 中的特定模式,例如整数、字符串或 slug 等。默认情况下,Django 提供了一些内置的路径转换器,如 <int>、<str>、&l…...
深度学习:神经网络中线性层的使用
深度学习:神经网络中线性层的使用 在神经网络中,线性层(也称为全连接层或密集层)是基础组件之一,用于执行输入数据的线性变换。通过这种变换,线性层可以重新组合输入数据的特征,并将其映射到新…...
【刷题】算法设计题+程序设计题【2】2019-2024
11.202019年真题*2BST二叉排序树分裂、双向冒泡排序 2019 真题 【2019 1】编写算法,将一棵二叉排序树 分解成两棵二叉排序树 t1和t2,使得t1中的所有结点关键字的值都小于x,t2中所有结点关键字都大于x。 typedef struct BSTNode{int data;str…...
搭建es环境
centos7搭建elasticsearch环境 首先考虑使用 Docker 来安装 Elasticsearch、Kibana 和 Logstash。在安装过程中,可能会遇到一些问题,但通过适当的方法可以解决。 docker pull docker.elastic.co/elasticsearch/elasticsearch:8.14.3 首先创建一个网络&a…...
阿里云和七牛云对象存储区别和实现
七牛云对象存储操作(QiniuUtil) 配置:使用 com.qiniu.storage.Configuration 类来配置上传设置,如指定区域(Region)和分片上传版本。上传管理器:通过 UploadManager 类来处理文件上传。认证&am…...
uniapp微信小程序接入airkiss插件进行WIFI配网
本文可参考uniapp小程序插件 一.申请插件 微信公众平台设置页链接:微信公众平台 登录您的小程序微信公众平台,进入设置页,在第三方设置->插件管理->添加插件中申请AiThinkerAirkissforWXMini插件,申请的插件appId为【wx6…...
03 —— Webpack 自动生成 html 文件
HtmlWebpackPlugin | webpack 中文文档 | webpack中文文档 | webpack中文网 安装 npm install --save-dev html-webpack-plugin 下载html-webpack-plugin本地软件包 npm i html-webpack-plugin --save-dev 配置webpack.config.js让webpack拥有插件功能 const HtmlWebpack…...
Python毕业设计选题:基于python的豆瓣电影数据分析可视化系统-flask+spider
开发语言:Python框架:flaskPython版本:python3.7.7数据库:mysql 5.7数据库工具:Navicat11开发软件:PyCharm 系统展示 系统首页 个人中心 管理员登录界面 管理员功能界面 电影管理 用户管理 系统管理 摘要…...
抽象类能使用final修饰吗?
不能。 在java中,抽象类不能使用final修饰。原因是final修饰符用于类不能被继承,而抽象类的主要用途就是被继承以提供基础实现或定义抽象方法供子类实现。这两个互相矛盾,因此不能同时使用。 具体解释 abstract修饰符:用于定义一个抽象类&…...
网站开发与设计实训报告1000字/做网站怎么做
前提是innodb情况下。 我们知道,MySQL执行的每一条语句势必会在某个事务下。在开启自动提交时,每一个语句就是一个事务,在自动提交关闭的情况下,commit命令就是一次事务的结束,也是另一个事务的开始。可…...
教育网站 php/免费发链接的网站
启动失败IDLE使用套接字在IDLE GUI进程和用户代码执行过程之间进行通信。无论何时Shellstart或重新启动,都必须建立连接。(后者用分隔线表示’RESTART’)。如果用户进程无法连接到GUI进程,则会显示一个失败的常见原因是用户编写的文件与标准库模块同名&a…...
wordpress常用代码/上海做网站优化
背景: 最近从某个数据网站获取到一份关于公司诉讼案件的数据表,在这里和大家分享一下我的分析方法。 数据清洗: 首先我们看一下数据信息,在这里我们需要以时间列作为索引,并把不需要的数据进行删除。 data pd.rea…...
网站建设招标书/网站域名查询官网
在VBA编程中,终止、退出及错误处理都是很有用的程序控制方法。那么,有哪些具体的方法呢?看到别人的培训资料里已有所总结,这里借花献佛一下。 代码1: 程序终止及退出方法 Option Explicit一、END语句作用:强…...
网站基本要素/佛山seo优化外包
写在前面 本文严禁转载,只限于学习交流。课件分享在这里了。还有人工智能标准化白皮书(2018版)也一并分享了。 文章目录绪论人工智能的定义与发展定义起源与发展各种认知观目前人工智能主要有以下三个学派:几种学派各自不足之处:研究目标与内…...