LoginSignup
4
2

More than 1 year has passed since last update.

Drag and DropAPIを生で触る / 追従する要素を自由にする方法

Last updated at Posted at 2022-07-19
1 / 23

 備考

特に面白くはない

ドラッグアンドドロップ周りのコードを書いたので備忘録件共有


ドラッグといえば

  • DnD API
  • Sortable
  • Vue.Draggable

ドラッグといえば

  • DnD API ← 生なのでめんどい
  • Sortable
  • Vue.Draggable

ドラッグといえば

  • DnD API
  • Sortable ← わりとカバーできる
  • Vue.Draggable

ドラッグといえば

  • DnD API
  • Sortable
  • Vue.Draggable ← SortableのWrapper

example.gif


めっちゃ便利


ドラッグといえば

  • DnD API

↓ ドキュメント読んで!

  • Sortable
  • Vue.Draggable

それでも生APIについて知りたい 


ドラッグといえば

  • DnD API ←←← これの話

ドラッグといえば


サンプルコード(MDN)

<div class="dropzone">
  <div id="draggable" draggable="true" ondragstart="event.dataTransfer.setData('text/plain',null)">
    This div is draggable
  </div>
</div>
<div class="dropzone"></div>
<div class="dropzone"></div>
<div class="dropzone"></div>
var dragged;

/* events fired on the draggable target */
document.addEventListener("drag", function(event) {

}, false);

document.addEventListener("dragstart", function(event) {
  // store a ref. on the dragged elem
  dragged = event.target;
  // make it half transparent
  event.target.style.opacity = .5;
}, false);

document.addEventListener("dragend", function(event) {
  // reset the transparency
  event.target.style.opacity = "";
}, false);

/* events fired on the drop targets */
document.addEventListener("dragover", function(event) {
  // prevent default to allow drop
  event.preventDefault();
}, false);

document.addEventListener("dragenter", function(event) {
  // highlight potential drop target when the draggable element enters it
  if (event.target.className == "dropzone") {
    event.target.style.background = "purple";
  }

}, false);

document.addEventListener("dragleave", function(event) {
  // reset background of potential drop target when the draggable element leaves it
  if (event.target.className == "dropzone") {
    event.target.style.background = "";
  }

}, false);

document.addEventListener("drop", function(event) {
  // prevent default action (open as link for some elements)
  event.preventDefault();
  // move dragged elem to the selected drop target
  if (event.target.className == "dropzone") {
    event.target.style.background = "";
    dragged.parentNode.removeChild( dragged );
    event.target.appendChild( dragged );
  }
}, false);

event handler desc
drag ondrag …ドラッグ項目 (要素や選択テキスト) がドラッグされた場合
dragend ondragend …ドラッグ操作の終了
dragenter ondragenter …ドラッグ項目が有効なドロップ対象に入った場合
dragexit ondragexit (en-US) …要素がドラッグ操作の選択対象でなくなった場合
dragleave ondragleave …ドラッグ項目が有効なドロップ対象を離れた場合
dragover ondragover …ドラッグ項目が有効なドロップ対象にドラッグされた場合、数百ミリ秒ごとに
dragstart ondragstart …ユーザーが項目をドラッグ開始した場合
drop ondrop …項目が有効なドロップ対象にドロップされた場合

HTMLの属性に dropable=true ってつける

  • つけないとドラッグ可能要素にならない
  • img タグはデフォルトで true
  • trueをつければdivでもなんでもドラッグ可能

これだけだと、ドラッグはできるが
ドロップができない


drop イベントを実装する

  • drop先のDOMがわかるので、自分自身を削除する
  • 元のDOMから自分自身を削除する

みたいなことがMDNの例に書いてある。

まぁ、MDNが情報源でなくてもいいんだけど


dragに追従する要素はどう決まる?


dragに追従する要素はどう決まる?

  • 基本:draggable=true の要素
  • DataTransfer.setDragImage() - Web API | MDN によって変更できる
  • できるが、setDragImage はdrag開始前に画面上にレンダリングされている画像 or DOMでなければならない
  • ドラッグ時にDOMを挿入したのではおそすぎる

深堀り:DataTransfer?

  • (dragstart イベントが発生した要素)から半透明の画像が生成され、ドラッグ中にマウスポインターに沿って移動します。
  • このメソッドは dragstart イベントハンドラー内で呼び出す必要があります。

何が問題か?

  • Vue.Draggable の @start イベントは、 @dragstart のラッパー的なやつなのでDataTransfarへアクセスすることができない

どうしよう?

  1. @dragstart (Vue2なら @dragstart.native) する
  2. 空のdivを DataTransfer.setDragImage でセットする
  3. dragover イベントでxy座標を取得してposition:absoluteにした生DOMのtop, leftをいじる
    • css のtransform: translate(top, left) を用いたほうが高速かも

あとは地道にチクチクしてください
おわり。

4
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
2