目录
[1. 效果展示](#1. 效果展示)
[2. 效果分析](#2. 效果分析)
[2.1 关键点](#2.1 关键点)
[2.2 实现方法](#2.2 实现方法)
[3. 代码实现](#3. 代码实现)
[3.1 html部分](#3.1 html部分)
[3.2 css部分](#3.2 css部分)
[3.3 js部分](#3.3 js部分)
[3.4 完整代码](#3.4 完整代码)
[4. 总结](#4. 总结)
1. 效果展示
如图所示,页面左侧有一个包含不同课程(如语文、数学等)的列表,页面右侧是一个表格,表示一周内每天的不同时间段。用户可以通过拖拽左侧的课程到右侧的时间表中,来安排课程。
2. 效果分析
**目标:**鼠标摁下左侧某一科目,拖拽到右侧某一位置放下,拖拽的课程就会嵌入到课表框当中
2.1 关键点
(1) 拖拽与放置逻辑的实现
(2) HTML与CSS布局的设计
2.2 实现方法
(1) 将拖拽过程分为 开始拖拽、允许放置、放置三部分分析。
(2) 页面主要由两部分组成------左侧是可拖动的课程项列表,右侧是一个表格,用于显示每周的时间安排。每个课程项都设定了 draggable = "true" 属性,使其可以被拖动。表格中的 <td> 元素(不包括第一列)是可以放置课程的目标区域。
(3) 通过 CSS 确保页面居中显示,并设置了 .box 容器的尺寸和边框。.left 和 .right 分别代表课程项列表和时间表的位置和大小。
3. 代码实现
接下来我会一步一步解说每段关键代码的含义。
3.1 html部分
<div class="box">
<div class="left">
<div class="yu" draggable="true">语文</div>
<div class="shu" draggable="true">数学</div>
<div class="ying" draggable="true">英语</div>
<div class="wu" draggable="true">物理</div>
<div class="hua" draggable="true">化学</div>
<div class="sheng" draggable="true">生物</div>
</div>
<div class="right">
<table>
<tr>
<th>时间/星期</th>
<th>星期一</th>
<th>星期二</th>
<th>星期三</th>
<th>星期四</th>
<th>星期五</th>
</tr>
<tr>
<td>08:00-09:00</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>10:00-11:00</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>11:00-12:00</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>12:00-13:00</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>14:00-15:00</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>15:00-16:00</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table>
</div>
</div>
左侧是课程列表, 该部分包含六个 <div> 元素,每个元素代表一门课程(如语文、数学等),并赋予了 draggable = "true" 属性,这意味着这些课程项可以被拖动。
右侧是时间表,提供了五个工作日(周一至周五)和六个上课时段的时间框架,使得用户可以直观地安排每周的课程。
3.2 css部分
.left {
width: 150px;
display: flex;
flex-direction: column;
justify-content: space-between;
gap: .7rem;
}
.left > div {
width: 100%;
height: 50px;
border: 1px solid black;
text-align: center;
line-height: 50px;
font-weight: bold;
letter-spacing: 4px;
cursor: move;
}
.yu { background: lawngreen; }
.shu { background: skyblue; }
.ying { background: mediumslateblue; }
.wu { background: aqua; }
.hua { background: violet; }
.sheng { background: navajowhite; }
.right {
width: 750px;
height: 400px;
overflow: auto;
}
css部分没什么好说的,按照自己的喜好随意编写即可。
3.3 js部分
const draggables = document.querySelectorAll('.left > div');
const droppables = document.querySelectorAll('.right td:not(:first-child)');
获取所有可拖动的课程项 和 所有可放置课程的时间段单元格(不包括第一列)。
draggables.forEach(draggable => {
draggable.addEventListener('dragstart', e => {
e.dataTransfer.setData('text/plain', e.target.className);
e.dataTransfer.dropEffect = 'move';
});
});
拖拽开始:: 当用户开始拖动一个课程项时,浏览器触发 dragstart 事件。在这个事件处理函数中,我们使用 setData 方法将被拖拽元素的类名作为数据存储在 Datatransfer 对象中。同时,设置drapEffect 属性为 'move',以表明这是一个移动操作。
droppables.forEach(droppable => {
droppable.addEventListener('dragover', e => {
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
});
});
允许放置: 当拖拽元素经过目标单元格时,浏览器会触发 dragover 事件。默认情况下,浏览器会阻止这个事件,所以我们需要调用 preventDefault() 来允许放置。同样地,我们设置 dropEffect为 'move',以便与 dragstart 中的设置相匹配。
droppable.addEventListener('drop', e => {
e.preventDefault();
const draggedItemClass = e.dataTransfer.getData('text/plain');
const draggedItem = document.querySelector(`.${draggedItemClass}`);
if (e.target.tagName === 'TD') {
e.target.textContent = draggedItem.textContent;
e.target.style.backgroundColor = window.getComputedStyle(draggedItem).backgroundColor;
}
});
放置:当用户释放鼠标按钮,拖拽元素被放置到目标单元格时,浏览器触发 drap 事件。在这个事件处理函数中,我们获取之前存储的数据(即课程项的类名),找到对应的课程项,并将其内容和背景颜色复制到目标单元格中。
3.4 完整代码
<!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>
<style>
body {
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #f0f0f0;
}
.box {
width: 1000px;
height: 600px;
border: 1px solid red;
display: flex;
justify-content: space-between;
align-items: center;
padding: 20px;
box-sizing: border-box;
}
.left {
width: 150px;
display: flex;
flex-direction: column;
justify-content: space-between;
gap: .7rem;
}
.left > div {
width: 100%;
height: 50px;
border: 1px solid black;
text-align: center;
line-height: 50px;
font-weight: bold;
letter-spacing: 4px;
cursor: move;
}
.yu { background: lawngreen; }
.shu { background: skyblue; }
.ying { background: mediumslateblue; }
.wu { background: aqua; }
.hua { background: violet; }
.sheng { background: navajowhite; }
.right {
width: 750px;
height: 400px;
overflow: auto;
}
table {
width: 100%;
border-collapse: collapse;
}
th, td {
width: 120px;
height: 50px;
border: 1px solid black;
text-align: center;
}
td {
cursor: pointer;
}
</style>
</head>
<body>
<div class="box">
<div class="left">
<div class="yu" draggable="true">语文</div>
<div class="shu" draggable="true">数学</div>
<div class="ying" draggable="true">英语</div>
<div class="wu" draggable="true">物理</div>
<div class="hua" draggable="true">化学</div>
<div class="sheng" draggable="true">生物</div>
</div>
<div class="right">
<table>
<tr>
<th>时间/星期</th>
<th>星期一</th>
<th>星期二</th>
<th>星期三</th>
<th>星期四</th>
<th>星期五</th>
</tr>
<tr>
<td>08:00-09:00</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>10:00-11:00</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>11:00-12:00</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>12:00-13:00</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>14:00-15:00</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>15:00-16:00</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</table>
</div>
</div>
<script>
// 获取所有可拖动的课程项
const draggables = document.querySelectorAll('.left > div');
// 获取所有可放置课程的时间段单元格(不包括第一列)
const droppables = document.querySelectorAll('.right td:not(:first-child)');
// 添加拖拽开始事件监听器
draggables.forEach(draggable => {
draggable.addEventListener('dragstart', e => {
e.dataTransfer.setData('text/plain', e.target.className);
e.dataTransfer.dropEffect = 'move';
});
});
// 添加拖拽进入和放置事件监听器
droppables.forEach(droppable => {
droppable.addEventListener('dragover', e => {
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
});
droppable.addEventListener('drop', e => {
e.preventDefault();
const draggedItemClass = e.dataTransfer.getData('text/plain');
const draggedItem = document.querySelector(`.${draggedItemClass}`);
if (e.target.tagName === 'TD') {
e.target.textContent = draggedItem.textContent;
e.target.style.backgroundColor = window.getComputedStyle(draggedItem).backgroundColor;
}
});
});
</script>
</body>
</html>
4. 总结
以上即是实现拖拽排课动效的全部内容。如果对您有所帮助,不妨点赞、关注+收藏,下次不迷路😀。
更多前端动效点击下方链接↓ ↓ ↓