【PR】を含みます。

フロントエンド

【JavaScript】ドラッグ&ドロップで要素を移動する方法とサンプルコード

JavaScript ドラッグ&ドロップで要素を移動する方法とサンプルコード

JavaScriptでドラッグ&ドロップ機能を実装する方法を2つのパターンで解説します。

エリア内での自由な要素移動と、リスト要素の並び替え機能の実装方法を、マウス・タッチ両対応のコードとともに紹介します。

また、実装に役立つ主要なライブラリについてもまとめています。

ドラッグ&ドロップでファイルアップロード機能を実装する方法は以下の記事で紹介しています。

あわせて読む
JavaScript ドラッグ&ドロップによるファイルアップロード機能を実装する方法と注意点
【JavaScript】ドラッグ&ドロップによるファイルアップロード機能を実装する方法と注意点

もくじ【サンプル】ドラッグ&ドロップによるファイルアップロード機能【実装コード】ドラッグ&ドロップによるファイルアップロード機能サーバーへのアップロード処理(擬似)よくあるエラーと対処法実装時の注意点 ...

【サンプル】ドラッグ&ドロップで特定のエリア内で要素を自由に動かす

Drag me

【実装コード】ドラッグ&ドロップで特定のエリア内で要素を自由に動かす

Copyをクリックするとコピーできます。

HTML
Copy
<div id="drag-area" class="drag-area">
  <div id="draggable-box" class="draggable-box">Drag me</div>
</div>
CSS
Copy
.drag-area {
  position: relative;
  width: 100%;
  height: 300px;
  border: 2px solid #ccc;
}
.draggable-box {
  display: flex;
  justify-content: center;
  align-items: center;
  position: absolute;
  width: 100px;
  height: 100px;
  text-align: center;
  color: #fff;
  background: #f09896;
  cursor: grab;
  touch-action: none;
}
.draggable-box.dragging {
  cursor: grabbing;
}
JavaScript
Copy
const box = document.getElementById('draggable-box');
const area = document.getElementById('drag-area');
let offsetX = 0;
let offsetY = 0;
let isDragging = false;
const getEventPosition = (e) => {
  if (e.touches) {
    return {
      x: e.touches[0].clientX,
      y: e.touches[0].clientY
    };
  }
  return {
    x: e.clientX,
    y: e.clientY
  };
};
const startDrag = (e) => {
  e.preventDefault();
  const pos = getEventPosition(e);
  const rect = box.getBoundingClientRect();
  offsetX = pos.x - rect.left;
  offsetY = pos.y - rect.top;
  isDragging = true;
  box.classList.add('dragging');
};
const duringDrag = (e) => {
  if (!isDragging) return;
  const pos = getEventPosition(e);
  const areaRect = area.getBoundingClientRect();
  let left = pos.x - areaRect.left - offsetX;
  let top = pos.y - areaRect.top - offsetY;
  const maxLeft = area.clientWidth - box.offsetWidth;
  const maxTop = area.clientHeight - box.offsetHeight;
  left = Math.max(0, Math.min(left, maxLeft));
  top = Math.max(0, Math.min(top, maxTop));
  box.style.left = left + 'px';
  box.style.top = top + 'px';
};
const endDrag = () => {
  isDragging = false;
  box.classList.remove('dragging');
};
const adjustPosition = () => {
  const areaRect = area.getBoundingClientRect();
  const maxLeft = area.clientWidth - box.offsetWidth;
  const maxTop = area.clientHeight - box.offsetHeight;
  const currentLeft = parseFloat(box.style.left) || 0;
  const currentTop = parseFloat(box.style.top) || 0;
  const newLeft = Math.max(0, Math.min(currentLeft, maxLeft));
  const newTop = Math.max(0, Math.min(currentTop, maxTop));
  box.style.left = newLeft + 'px';
  box.style.top = newTop + 'px';
};
// === イベント登録 ===
// マウス
box.addEventListener('mousedown', startDrag);
document.addEventListener('mousemove', duringDrag);
document.addEventListener('mouseup', endDrag);
// タッチ
box.addEventListener('touchstart', startDrag, { passive: false });
document.addEventListener('touchmove', duringDrag, { passive: false });
document.addEventListener('touchend', endDrag);
window.addEventListener('resize', adjustPosition);

【サンプル】ドラッグ&ドロップでリスト要素を並び替える

  • アイテム1
  • アイテム2
  • アイテム3
  • アイテム4

【実装コード】ドラッグ&ドロップでリスト要素を並び替える

Copyをクリックするとコピーできます。

HTML
Copy
<ul id="sortable-list" class="sortable-list">
  <li class="sortable-item">アイテム1</li>
  <li class="sortable-item">アイテム2</li>
  <li class="sortable-item">アイテム3</li>
  <li class="sortable-item">アイテム4</li>
</ul>
CSS
Copy
.sortable-list {
  margin: 0;
  padding: 0;
  list-style: none;
}
.sortable-item {
  margin: 4px 0;
  padding: 12px;
  background: #fff6f6;
  border: 1px solid #ccc;
  transition: 0.3s ease;
  cursor: grab;
}
.dragging {
  opacity: 0.4;
}
JavaScript
Copy
const list = document.getElementById('sortable-list');
let draggingItem = null;
const getDragAfterElement = (container, y) => {
  const items = [...container.querySelectorAll('.sortable-item:not(.dragging)')];
  return items.reduce((closest, child) => {
    const box = child.getBoundingClientRect();
    const offset = y - (box.top + box.height / 2);
    if (offset < 0 && offset > closest.offset) {
      return { offset: offset, element: child };
    } else {
      return closest;
    }
  }, { offset: Number.NEGATIVE_INFINITY }).element;
};
// マウス
list.querySelectorAll('.sortable-item').forEach((item) => {
  item.setAttribute('draggable', 'true');
  item.addEventListener('dragstart', (e) => {
    draggingItem = item;
    item.classList.add('dragging');
  });
  item.addEventListener('dragend', () => {
    if (draggingItem) {
      draggingItem.classList.remove('dragging');
      draggingItem = null;
    }
  });
});
list.addEventListener('dragover', (e) => {
  e.preventDefault();
  const afterElement = getDragAfterElement(list, e.clientY);
  if (afterElement == null) {
    list.appendChild(draggingItem);
  } else {
    list.insertBefore(draggingItem, afterElement);
  }
});
// タッチ
let touchDraggingItem = null;
list.querySelectorAll('.sortable-item').forEach((item) => {
  item.addEventListener('touchstart', (e) => {
    touchDraggingItem = item;
    item.classList.add('dragging');
  });
  item.addEventListener('touchmove', (e) => {
    e.preventDefault(); // スクロール防止
    const touchY = e.touches[0].clientY;
    const afterElement = getDragAfterElement(list, touchY);
    if (afterElement == null) {
      list.appendChild(touchDraggingItem);
    } else {
      list.insertBefore(touchDraggingItem, afterElement);
    }
  });
  item.addEventListener('touchend', () => {
    if (touchDraggingItem) {
      touchDraggingItem.classList.remove('dragging');
      touchDraggingItem = null;
    }
  });
});

並び替え・自由移動ライブラリ比較表

ライブラリ名 並び替え対応(リスト) 自由移動対応(XY座標) スマホ対応 特徴・備考
SortableJS 可能 不可 対応 軽量・簡単。
並び替え特化。
自由移動は非対応。
Interact.js 不可 可能 対応 境界制限・スナップ・リサイズも可能。
自由移動なら最有力。
GridStack.js 可能 グリッド状に動かせる 対応 ダッシュボード風のレイアウトに強い。

用途別おすすめ

やりたいこと名 おすすめライブラリ
シンプルなリストの並び替え SortableJS
自由な位置に動かしたい(エリア内など) Interact.js
並び替え+自由移動(グリッド風UI) GridStack.js

まとめ

JavaScriptでドラッグ&ドロップ機能を実装する方法を2つのパターンに分けて紹介しました。

  • エリア内で自由に要素を移動:カスタムUIやゲーム要素の実装に最適
  • リストの並び替え:タスクリストや管理画面での項目の並び替えに活用可能
  • マウス・タッチ両対応:モバイルデバイスでも快適に操作可能

自前実装することで、柔軟なカスタマイズが可能です。

また、必要に応じてSortableJSやInteract.jsなどのライブラリを活用することで、より高度な機能を実装することもできます。

ぜひ、ご自身のプロジェクトに合わせてカスタマイズしてみてください。

ドラッグ&ドロップでファイルアップロード機能を実装する方法は以下の記事で紹介しています。

あわせて読む
JavaScript ドラッグ&ドロップによるファイルアップロード機能を実装する方法と注意点
【JavaScript】ドラッグ&ドロップによるファイルアップロード機能を実装する方法と注意点

もくじ【サンプル】ドラッグ&ドロップによるファイルアップロード機能【実装コード】ドラッグ&ドロップによるファイルアップロード機能サーバーへのアップロード処理(擬似)よくあるエラーと対処法実装時の注意点 ...

-フロントエンド
-