HTML5拖拽API学习 托拽排序和可托拽课程表

文章目录

      • 前言
      • 拖拽API核心概念
      • 拖拽式使用流程
      • 例子
      • 注意事项
      • 综合例子🌰 可拖拽课程表
      • 拖拽排序

在这里插入图片描述

前言

前端拖拽功能让网页元素可以通过鼠标或触摸操作移动。HTML5 提供了标准的拖拽API,简化了拖放操作的实现。以下是拖拽API的基本使用指南:

拖拽API核心概念

  1. draggable属性:设置元素的draggable="true"属性,允许用户拖动该元素。
    <div draggable="true">可拖动元素</div>
  1. dragstart事件:拖动开始时触发,可以设置拖动数据。
    const draggableElement = document.querySelector('div');
    draggableElement.addEventListener('dragstart', (event) => {
      event.dataTransfer.setData('text/plain', '拖动数据');
 });
  1. dragover事件:拖动元素在目标区域上方时触发,需要调用event.preventDefault()以允许放置。
    const dropZone = document.querySelector('#dropZone');
    dropZone.addEventListener('dragover', (event) => {
      event.preventDefault(); // 允许放置
    });
  1. drop事件:拖动元素放置到目标区域时触发,可以获取拖动数据。
    dropZone.addEventListener('drop', (event) => {
      event.preventDefault();
      const data = event.dataTransfer.getData('text/plain');
      console.log('放置的数据:', data);
    });
  1. dragend事件:拖动操作结束时触发,用于清理拖动状态或重置样式。
draggableElement.addEventListener('dragend', () => {
      draggableElement.style.backgroundColor = ''; // 重置样式
    });

拖拽式使用流程

  1. 设置可拖拽元素:在HTML中为元素添加draggable="true"属性。
  2. 处理拖拽开始事件:在dragstart事件中设置拖拽数据。
  3. 设置目标区域:通过dragover事件处理,允许放置操作。
  4. 处理放置事件:在drop事件中获取数据并处理放置逻辑。
  5. 清理拖拽操作:在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>

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

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

相关文章

华为Ensp模拟器配置OSPF路由协议

目录 简介 实验步骤 Pc配置 路由器配置 OSPF配置 交换机配置 简介 开放式最短路径优先 (OSPF) 协议深度解析 简介 开放式最短路径优先&#xff08;Open Shortest Path First, OSPF&#xff09;是一种内部网关协议&#xff08;IGP&#xff09;&#xff0c;用于在自治系统…

【最新鸿蒙应用开发】——合理使用自定义弹框

自定义弹窗选型 合理选择不同的系统能力实现弹窗&#xff0c;有利于提升应用开发效率&#xff0c;实现更好的功能需求&#xff0c;因此了解自定义弹窗的选型和差异非常重要。在应用开发中&#xff0c;为了选择出合适的弹窗选型&#xff0c;从使用场景上&#xff0c;需要重点关…

自动化爬虫Selenium

自动化爬虫Selenium 这篇文章, 我们将要学习自动化爬虫的知识啦。 目录 1.Selenium的基本操作 2.用Selenuim获取数据 3.当当网数据获取 4.实战 一、Selenium的基本操作 首先, 我们在使用Selenium之前, 需要做两件事情。第一件事情, 就是安装第三方库, 第二件事情, 就是…

开源可视化工具对比:JimuReport VS DataEase

在当今数据驱动的时代&#xff0c;高效的数据可视化工具成为企业洞察业务、做出决策的关键利器。那对于企业来讲如何选择BI产品呢&#xff1f; 在开源可视化工具的领域中&#xff0c;JimuReport和DataEase 以其独特的优势脱颖而出&#xff0c;究竟谁更胜一筹呢&#xff1f;让我…

Jenkins的环境部署

day22 回顾 Jenkins 简介 官网Jenkins Jenkins Build great things at any scale The leading open source automation server, Jenkins provides hundreds of plugins to support building, deploying and automating any project. 用来构建一切 其实就是用Java写的一个项目…

Ubuntu22.04配置强化学习环境及运行相关Demo

什么是强化学习 强化学习&#xff08;Reinforcement Learning&#xff0c;简称 RL&#xff09;是机器学习中的一个重要分支&#xff0c;属于一种基于试错机制的学习方法。它通过让智能体&#xff08;Agent&#xff09;与环境&#xff08;Environment&#xff09;进行交互&…

AI 写作(一):开启创作新纪元(1/10)

一、AI 写作&#xff1a;重塑创作格局 在当今数字化高速发展的时代&#xff0c;AI 写作正以惊人的速度重塑着创作格局。AI 写作在现代社会中占据着举足轻重的地位&#xff0c;发挥着不可替代的作用。 随着信息的爆炸式增长&#xff0c;人们对于内容的需求日益旺盛。AI 写作能够…

丹摩征文活动 | AI创新之路,DAMODEL助你一臂之力GPU

目录 前言—— DAMODEL&#xff08;丹摩智算&#xff09; 算力服务 直观的感受算力提供商的强大​ 平台功能介绍​ 镜像选择 云磁盘创建 总结 前言—— 只需轻点鼠标,开发者便可拥有属于自己的AI计算王国 - 从丰富的GPU实例选择,到高性能的云磁盘,再到预配置的深度学习…

echarts的图例换行并对齐

现状&#xff1a; 期望&#xff1a; 实现方式&#xff1a; 通过对legend的formatter和textStyle组合设置宽度来实现&#xff0c;代码如下 这里会出现一个问题&#xff0c;发现设置了width没有效果&#xff0c;刚开始以为是宽度给的不够&#xff0c;然后发现并不是&#xff0c…

go-zero(二) api语法和goctl应用

go-zero api语法和goctl应用 在实际开发中&#xff0c;我们更倾向于使用 goctl 来快速生成代码。 goctl 可以根据 api快速生成代码模板&#xff0c;包括模型、逻辑、处理器、路由等&#xff0c;大幅提高开发效率。 一、构建api demo 现在我们通过 goctl 创建一个最小化的 HT…

Windows Server 2022 Web1

载入靶机&#xff0c;看到相关描述&#xff1a; 进入虚拟机发现桌面有phpstudy和解题两个软件&#xff1a; 打开解题.exe&#xff0c;发现里面是一些问题&#xff0c;接下来就需要获取相关信息&#xff1a; 1、shell密码 2、IP地址 3、隐藏账户名称 4、挖矿程序的矿池域名 打…

经典的网络安全技术

以我的理解&#xff0c;“黑客”大体上应该分为“正”、“邪”两类&#xff0c;正派黑客依靠自己掌握的知识帮助系统管理员找出系统中的漏洞并加以完善&#xff0c;而邪派黑客则是通过各种黑客技能对系统进行攻击、入侵或者做其他一些有害于网络的事情&#xff0c;因为邪派黑客…

【TDOA最小二乘解算】两步最小二乘迭代的TDOA解算方法,适用于二维平面、自适应锚点(附MATLAB代码)

本文所述的MATLAB代码实现了一个基于两步加权最小二乘法的二维目标定位算法&#xff0c;利用多个锚点&#xff08;基站&#xff09;和时间差到达&#xff08;TDOA&#xff09;数据来估计未知目标的位置。 文章目录 运行结果代码代码功能概述代码结构和详细说明初始化部分参数和…

VideoCrafter模型部署教程

一、介绍 VideoCrafter是一个功能强大的AI视频编辑和生成工具&#xff0c;它结合了深度学习和机器学习技术&#xff0c;为用户提供了便捷的视频制作和编辑体验。 系统&#xff1a;Ubuntu22.04系统&#xff0c;显卡&#xff1a;4090&#xff0c;显存&#xff1a;24G 二、基础…

【图像压缩感知】论文阅读:Content-Aware Scalable Deep Compressed Sensing

tips&#xff1a; 本文为个人阅读论文的笔记&#xff0c;仅作为学习记录所用。本文参考另一篇论文阅读笔记 Title&#xff1a; Content-Aware Scalable Deep Compressed Sensing Journal&#xff1a; TIP 2022 代码链接&#xff1a; https://github.com/Guaishou74851/CASNet…

AMD(Xilinx) FPGA配置Flash大小选择

目录 1 FPGA配置Flash大小的决定因素2 为什么选择的Flash容量大小为最小保证能够完成整个FPGA的配置呢&#xff1f; 1 FPGA配置Flash大小的决定因素 在进行FPGA硬件设计时&#xff0c;选择合适的配置Flash是我们进行硬件设计必须考虑的&#xff0c;那么配置Flash大小的选择由什…

统⼀数据返回格式快速⼊⻔

为什么会有统⼀数据返回&#xff1f; 其实统一数据返回是运用了AOP&#xff08;对某一类事情的集中处理&#xff09;的思维。 优点&#xff1a; 1.⽅便前端程序员更好的接收和解析后端数据接⼝返回的数据。 2.降低前端程序员和后端程序员的沟通成本&#xff0c;因为所有接⼝都…

window 中安装 php 环境

window 中安装 php 环境 一、准备二、下载三、安装四、测试 一、准备 安装前需要安装 Apache &#xff0c;可以查看这篇博客。 二、下载 先到这里下载 这里选择版本为“VS16 x64 Thread Safe”&#xff0c;这个版本不要选择线程安全的&#xff0c;我试过&#xff0c;会缺少文…

HarmonyOS Next 关于页面渲染的性能优化方案

HarmonyOS Next 关于页面渲染的性能优化方案 HarmonyOS Next 应用开发中&#xff0c;用户的使用体验至关重要。其中用户启动APP到呈现页面主要包含三个步骤&#xff1a; 框架初始化页面加载布局渲染 从页面加载到布局渲染中&#xff0c;主要包含了6个环节&#xff1a; 执行页…

【Linux网络编程】简单的UDP套接字

目录 一&#xff0c;socket编程的相关说明 1-1&#xff0c;sockaddr结构体 1-2&#xff0c;Socket API 二&#xff0c;基于Udp协议的简单通信 三&#xff0c;UDP套接字的应用 3-1&#xff0c;实现英译汉字典 一&#xff0c;socket编程的相关说明 Socket编程是一种网络通信…