首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

HTML 表格欄位拖曳調整寬度完整實作指南

     編輯:Java 相關知識

前言

在 Web 開發中,讓使用者能像 Excel 一樣拖曳調整表格欄寬,是提升資料呈現體驗的關鍵功能。早期常見的做法利用 IE 專屬的 setCapture() 與 expression(),雖然能跑,但相容性極差、操作手感也不好。本文將帶你從經典舊碼出發,重構出一個現代、跨瀏覽器、觸控友善的表格欄寬拖曳方案。

核心邏輯:三階段事件流

拖曳調整寬度本質上是「按下 → 移動 → 釋放」的三階段流程:

  1. mousedown / touchstart:記錄起始座標與目標欄目前寬度,綁定全域移動/釋放事件。
  2. mousemove / touchmove:依位移量即時計算新寬度,同步更新 <th>、<col> 或 CSS 變數。
  3. mouseup / touchend:解除全域事件,完成一次調整。

現代化重構範例(Vanilla JS + CSS)

<!DOCTYPE html>
<html lang="zh-Hant">
<head>
  <meta charset="UTF-8">
  <title>表格欄寬拖曳調整 Demo</title>
  <style>
    table { border-collapse: collapse; width: 100%; table-layout: fixed; }
    th, td { border: 1px solid #ddd; padding: 8px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
    th { background: #f5f5f5; position: relative; user-select: none; }
    .resize-handle {
      position: absolute; top: 0; right: 0; width: 6px; height: 100%;
      background: transparent; cursor: col-resize; z-index: 1;
      transition: background 0.15s;
    }
    .resize-handle:hover, .resize-handle.dragging { background: #1890ff; opacity: 0.6; }
    /* 觸控裝置加大熱區 */
    @media (pointer: coarse) { .resize-handle { width: 14px; } }
  </style>
</head>
<body>
  <table id="dataTable">
    <thead>
      <tr>
        <th>姓名<span class="resize-handle" data-col="0"></span></th>
        <th>部門<span class="resize-handle" data-col="1"></span></th>
        <th>職稱<span class="resize-handle" data-col="2"></span></th>
        <th>備註<span class="resize-handle" data-col="3"></span></th>
      </tr>
    </thead>
    <tbody>
      <tr><td>張三</td><td>研發部</td><td>工程師</td><td>核心成員</td></tr>
      <tr><td>李四</td><td>行銷部</td><td>專員</td><td>負責推廣</td></tr>
    </tbody>
  </table>

  <script>
  (() => {
    const table = document.getElementById('dataTable');
    const handles = table.querySelectorAll('.resize-handle');
    let startX = 0, startWidth = 0, currentHandle = null, currentTh = null;

    const onMove = (clientX) => {
      if (!currentHandle) return;
      const dx = clientX - startX;
      const newWidth = Math.max(40, startWidth + dx); // 最小 40px
      currentTh.style.width = newWidth + 'px';
      // 若使用 <colgroup><col> 也要同步更新對應 col.style.width
    };

    const onUp = () => {
      if (currentHandle) currentHandle.classList.remove('dragging');
      document.removeEventListener('mousemove', mouseMoveHandler);
      document.removeEventListener('mouseup', onUp);
      document.removeEventListener('touchmove', touchMoveHandler, { passive: false });
      document.removeEventListener('touchend', onUp);
      currentHandle = currentTh = null;
    };

    const mouseMoveHandler = e => onMove(e.clientX);
    const touchMoveHandler = e => { e.preventDefault(); onMove(e.touches[0].clientX); };

    handles.forEach(handle => {
      const th = handle.closest('th');
      const colIndex = +handle.dataset.col;

      const start = (clientX) => {
        currentHandle = handle; currentTh = th;
        startX = clientX; startWidth = th.offsetWidth;
        handle.classList.add('dragging');
        document.addEventListener('mousemove', mouseMoveHandler);
        document.addEventListener('mouseup', onUp);
        document.addEventListener('touchmove', touchMoveHandler, { passive: false });
        document.addEventListener('touchend', onUp);
      };

      handle.addEventListener('mousedown', e => { e.preventDefault(); start(e.clientX); });
      handle.addEventListener('touchstart', e => { start(e.touches[0].clientX); }, { passive: false });
    });
  })();
  </script>
</body>
</html>

進階優化重點

  • 效能:僅更新樣式而非重排整個 DOM;大量資料時搭配 requestAnimationFrame 節流。
  • 持久化:調整結束後將各欄寬存入 localStorage,下次載入自動套用。
  • 無障礙:為 handle 加上 role="separator"、aria-orientation="vertical"、tabindex="0",並支援鍵盤 ←/→ 微調。
  • 框架整合:Vue/React 可封裝成 <ResizableTable> 元件,透過 v-model:columnWidths 雙向綁定。

常見坑點快速排查

現象原因解法
拖曳時文字被選取瀏覽器預設行為CSS user-select: none 或 e.preventDefault()
欄寬調整後表格總寬度變了table-layout: auto強制 table-layout: fixed 並指定總寬
手機上無法拖曳缺少 touch 事件或 passive: false同步綁定 touchstart/move/end 並 preventDefault

結語

拋棄舊式 IE 專屬寫法,改用標準事件模型與 CSS 變數,不只相容性大幅提升,程式碼也更易維護。下次需要表格欄寬拖曳時,直接套用上述模式即可快速上線。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved