舉例說明js如何拖拽排序?

王铁柱6發表於2024-11-27

JS 拖拽排序的實現方法有很多,這裡提供一個基於 HTML5 Drag and Drop API 的例子,並解釋關鍵步驟和程式碼:

<!DOCTYPE html>
<html>
<head>
<title>拖拽排序</title>
<style>
  #container {
    display: flex;
  }

  .item {
    width: 100px;
    height: 50px;
    background-color: lightblue;
    margin: 10px;
    text-align: center;
    line-height: 50px;
    cursor: move;
    user-select: none; /* 防止拖拽時選中文字 */
  }

  .dragging {
    opacity: 0.5;
  }

  .over {
    background-color: lightgreen;
  }
</style>
</head>
<body>

<div id="container">
  <div class="item" draggable="true">Item 1</div>
  <div class="item" draggable="true">Item 2</div>
  <div class="item" draggable="true">Item 3</div>
</div>

<script>
  const container = document.getElementById('container');
  const items = document.querySelectorAll('.item');

  let draggedItem = null;

  items.forEach(item => {
    item.addEventListener('dragstart', (e) => {
      draggedItem = item;
      item.classList.add('dragging');
      e.dataTransfer.effectAllowed = 'move'; // 設定允許的操作為移動
      e.dataTransfer.setData('text/plain', null); //  這行對於 Firefox 很重要
    });

    item.addEventListener('dragend', () => {
      draggedItem.classList.remove('dragging');
      items.forEach(item => item.classList.remove('over')); // 清除所有 over 樣式
      draggedItem = null;
    });

    item.addEventListener('dragover', (e) => {
      e.preventDefault(); //  必須preventDefault(),否則drop事件不會觸發
      e.dataTransfer.dropEffect = 'move'; //  視覺反饋
      const target = e.target.closest('.item'); // 確保目標是.item元素

      if (target && target !== draggedItem) {
        const rect = target.getBoundingClientRect();
        const offsetY = e.clientY - rect.top;
        const targetCenter = rect.height / 2;

        if (offsetY < targetCenter) {
          container.insertBefore(draggedItem, target);
        } else {
          container.insertBefore(draggedItem, target.nextSibling);
        }
        items.forEach(item => item.classList.remove('over')); // 清除之前的 over 樣式
        target.classList.add('over');
      }
    });

    item.addEventListener('dragenter', (e) => {
      const target = e.target.closest('.item');
      if (target && target !== draggedItem) {
          target.classList.add('over');
      }
    });

    item.addEventListener('dragleave', (e) => {
      const target = e.target.closest('.item');
      if (target) {
          target.classList.remove('over');
      }
    });


    item.addEventListener('drop', (e) => {
      e.preventDefault(); // 阻止預設行為
    });
  });
</script>

</body>
</html>

關鍵步驟和程式碼解釋:

  1. 設定draggable屬性: 在需要拖拽的元素上設定 draggable="true"

  2. dragstart事件: 當開始拖拽元素時觸發。在這個事件中,記錄被拖拽的元素,並設定拖拽資料和效果。e.dataTransfer.setData('text/plain', null); 對於 Firefox 正常工作至關重要,即使你不需要傳輸任何資料。

  3. dragend事件: 拖拽結束時觸發。清除拖拽相關的樣式和變數。

  4. dragover事件: 當拖拽的元素在目標元素上方時觸發。必須呼叫 e.preventDefault() 才能觸發 drop 事件。此事件用於處理元素插入位置的邏輯。 透過計算滑鼠相對於目標元素中心的位置來確定插入位置。

  5. dragenterdragleave 事件: 用於新增和移除目標元素的 hover 樣式,提供視覺反饋。使用 `closest

相關文章