
在现代 Web 应用中,交互式数据操作已成为提升用户体验的重要手段。其中,通过拖拽直接交换单元格内容是一种直观、高效的操作方式,广泛应用于课程表编排、任务看板、配置管理等场景。本文将详细介绍如何使用纯原生 JavaScript(无任何框架依赖)实现一个支持单元格拖拽交换的 HTML 表格,并提供完整可运行的源代码。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>现代 JS 动态拖动表格实现</title>
<style>
:root {
--pre-color: lavender;
--end-color: #ffccff;
--normal-bg: transparent;
}
table {
width: 70%;
margin: 20px auto;
border-collapse: collapse;
font-size: 14px;
border: 1px solid #000;
}
th {
height: 32px;
font-weight: bold;
background-color: #ccc;
border-bottom: 2px solid #000;
}
td {
width: 25%;
height: 32px;
border: 1px solid #000;
text-align: center;
user-select: none; /* 禁止选中文字 */
cursor: grab;
}
td.dragging {
cursor: grabbing;
background-color: var(--pre-color);
}
td.hover-target {
background-color: var(--end-color);
}
#drag-helper {
position: absolute;
border: 1px solid #000;
background-color: var(--end-color);
pointer-events: none; /* 不拦截鼠标事件 */
z-index: 1000;
display: none;
text-align: center;
line-height: 32px;
font-size: 14px;
box-shadow: 2px 2px 4px rgba(0,0,интегрированный,0.2);
}
</style>
</head>
<body>
<table id="draggableTable">
<thead>
<tr>
<th colspan="4">拖动交换单元格内容</th>
</tr>
</thead>
<tbody>
<tr><td>Java</td><td>Java One</td><td>JBuilder</td><td>Struts</td></tr>
<tr><td>C++</td><td>Visual Studio</td><td>Office</td><td>Windows</td></tr>
<tr><td>PhotoShop</td><td>Java</td><td>Illustrator</td><td>PageMaker</td></tr>
<tr><td>Cartoon</td><td>Telephone</td><td>China</td><td>USA</td></tr>
<tr><td>Java</td><td>Java One</td><td>JBuilder</td><td>Stuts</td></т></tr>
<tr><td>C++</td><td>Visual Studio</td><td>Office</td><td>Windows</td></tr>
<tr><td>PhotoShop</td><td>Flash</td><td>Illustrator</td><td>PageMaker</td></tr>
<tr><td>Cartoon</td><td>Telephone</td><td>China</td><td>USA</td></tr>
</tbody>
</table>
<div id="drag-helper"></div>
<script>
/**
* created by yzh 2002.4.12
* 可以实现表格内容的内部拖动
* 确保中间过度层的存在,id为指定
* 请大家引用时保留这段作者声明,此代码为开源代码;使用不受限制,欢迎大家采用本人所写JS动态拖动表格实现代码。
*/
class DraggableTable {
constructor(tableId) {
this.table = document.getElementById(tableId);
this.helper = document.getElementById('drag-helper');
this.draggedCell = null;
this.originalContent = '';
this.originalBg = '';
// 绑定事件
this.table.addEventListener('mousedown', (e) => this.onMouseDown(e));
document.addEventListener('mousemove', (e) => this.onMouseMove(e));
document.addEventListener('mouseup', (e) => this.onMouseUp(e));
// 防止文本选中
this.table.addEventListener('selectstart', (e) => e.preventDefault());
}
onMouseDown(e) {
const cell = e.target.closest('td');
if (!cell) return;
e.preventDefault(); // 阻止默认行为(如文本选中)
this.draggedCell = cell;
this.originalContent = cell.textContent;
this.originalBg = window.getComputedStyle(cell).backgroundColor;
// 设置拖动样式
cell.classList.add('dragging');
// 初始化 helper 层
const rect = cell.getBoundingClientRect();
this.helper.style.width = `${rect.width}px`;
this.helper.style.height = `${rect.height}px`;
this.helper.textContent = this.originalContent;
this.helper.style.display = 'block';
this.updateHelperPosition(e.clientX, e.clientY);
// 记录初始偏移
this.offsetX = e.clientX - rect.left;
this.offsetY = e.clientY - rect.top;
}
onMouseMove(e) {
if (!this.draggedCell) return;
// 更新 helper 位置
this.updateHelperPosition(e.clientX - this.offsetX, e.clientY - this.offsetY);
// 检测 hover 的目标单元格
const target = document.elementFromPoint(e.clientX, e.clientY);
const hoverCell = target?.closest?.('td');
// 清除之前的 hover 样式
document.querySelectorAll('td.hover-target').forEach(td => {
td.classList.remove('hover-target');
});
// 设置新的 hover 样式(不能是自身)
if (hoverCell && hoverCell !== this.draggedCell && hoverCell.closest('table') === this.table) {
hoverCell.classList.add('hover-target');
}
}
onMouseUp(e) {
if (!this.draggedCell) return;
// 查找最终 hover 的单元格
const target = document.elementFromPoint(e.clientX, e.clientY);
const dropCell = target?.closest?.('td');
// 执行交换
if (dropCell && dropCell !== this.draggedCell && dropCell.closest('table') === this.table) {
// 交换内容
const temp = dropCell.textContent;
dropCell.textContent = this.originalContent;
this.draggedCell.textContent = temp;
}
// 清理状态
this.draggedCell.classList.remove('dragging');
this.draggedCell.style.backgroundColor = this.originalBg;
this.helper.style.display = 'none';
document.querySelectorAll('td.hover-target').forEach(td => {
td.classList.remove('hover-target');
});
this.draggedCell = null;
}
updateHelperPosition(x, y) {
this.helper.style.left = `${x}px`;
this.helper.style.top = `${y}px`;
}
}
// 初始化
document.addEventListener('DOMContentLoaded', () => {
new DraggableTable('draggableTable');
});
</script>
</body>
</html>原作地址:https://www.cnblogs.com/BlogNetSpace/archive/2006/03/24/358034.html
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。