首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >原生js实现可拖拽表格

原生js实现可拖拽表格

原创
作者头像
jack.yang
发布2026-03-31 16:51:05
发布2026-03-31 16:51:05
1600
举报

在现代 Web 应用中,交互式数据操作已成为提升用户体验的重要手段。其中,通过拖拽直接交换单元格内容是一种直观、高效的操作方式,广泛应用于课程表编排、任务看板、配置管理等场景。本文将详细介绍如何使用纯原生 JavaScript(无任何框架依赖)实现一个支持单元格拖拽交换的 HTML 表格,并提供完整可运行的源代码。

代码语言:txt
复制
<!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 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档