当前位置: 首页 > article >正文

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>

http://www.kler.cn/a/399085.html

相关文章:

  • Python 网络爬虫入门教程
  • uniapp 实现tabbar分类导航及滚动联动效果
  • Javascript高级—函数柯西化
  • Jenkins的pipeline Script的 每个组件的详细讲解
  • ES6标准-Promise对象
  • PCL 三维重建 耳切三角剖分算法
  • 使用CNN进行验证码识别:深度学习与图像预处理教程
  • conda创建 、查看、 激活、删除 python 虚拟环境
  • 高效协作:前后端合作规范与应对策略优化
  • Day18 Nim游戏
  • 搜维尔科技:SenseGlove触觉反馈手套开箱+场景测试
  • layui.all.js:2 Uncaught Error: Syntax error, unrecognized expression
  • QDataStream
  • vue项目使用eslint+prettier管理项目格式化
  • 阿里巴巴通义灵码推出Lingma SWE-GPT:开源模型的性能新标杆
  • B-树特点以及插入、删除数据过程
  • 使用Python编写一个简单的网页爬虫,从网站抓取新闻标题和链接。
  • [C++] 异常
  • Upload-Labs-Linux1学习笔迹 (图文介绍)
  • 力扣周赛:第424场周赛
  • 【机器学习】朴素贝叶斯算法
  • 基于K8S1.28.2实验rook部署ceph
  • FPGA开发-逻辑分析仪的应用-数字频率计的设计
  • 关于做完 C# 项目的问题总结
  • STM32设计智能翻译手势识别加算法系统
  • 基于OpenCV的自制Python访客识别程序