JavaScriptでドラッグ&ドロップの実装

2021年4月13日火曜日

JavaScript

タイトル通りJavaScript(以下JS)を使用したドラッグ&ドロップ(以下D&D)の実装ということで、今日は久しぶりにプログラミング関連の記事を。といっても詳しく解説するとかではなく、自分のした作業記録というか日記みたいなものですが。いじっていたプログラムのレスポンシブ対応を考えていた際にD&Dでなんとか誤魔化せないかな?と思い至り、調べ始めました。ただ調べてみるとHTML5から導入されている機能についてはスマホ対応になっていない。そしてjQuery等のライブラリを使用したものばかりがヒットする。できれば純粋なJSで組みたいところ。そう考えながら調べていて最初に辿り記事がこちら↓

OGP画像



実は僕が以前にJS学習で使用させていただいていたサイトです。途中でコードいじりへ方向転換したのでパート1しか目を通していなかったのですが…やっぱりパート2以降に実践で必要な知識が多かったみたいで。困って検索していると↑のサイトに辿りつくことが何度かありました。詳しく説明されていますのでD&Dのやり方については理解できました。しかし↑の記事のコードではタッチデバイスには対応できない。それに動作に関して少し不満を感じる部分もある。ということで引き続き調べることに。次に辿り着いたのが↓の記事。



タッチイベントについて分かりやすく解説されています。というか大雑把に目を通していたせいで気づいていませんでしたけれど、僕がハマったポイントについてもちゃんと言及されていましたね。たったいま記事を書きながら気づきました。なんにしても↑二つの記事情報を合わせて考えればスマホ対応のD&Dが実装できそうだな…と思いましたが、何気なく検索しているとJSのみでD&D実装をしたコードの紹介記事も発見。あるのならば参考にさせてもらおうとチェック。



ほぼほぼ僕が求めていたコードでした。なのでもうこれで良いかな?という思考になり、そのまま導入しようとするも不具合がでる。ならば考えるしかない。そしてなんだかんだで結構な時間をかけコードをいじっていくことになりました。そうして↑三つの記事を参考にしてできたコードがこちら↓



//Drop and Drag
{
  let elements = [].slice.call(document.getElementsByClassName("drag-and-drop"));
  let x;
  let y;
  let mupBind;
  let mmoveBind;
  let event;

  for(let i = 0; i < elements.length; i++) {
      elements[i].addEventListener("mousedown", mdown, false);
      elements[i].addEventListener("touchstart", mdown, false);
  }
  //クリック・タッチ時の処理
  function mdown(e) {
      overlapSort.bind(this)(); 
          
      if(e.type === "mousedown") {
          event = e;
      } else {
          event = e.changedTouches[0];
      }
      x = event.pageX - this.offsetLeft;
      y = event.pageY - this.offsetTop;

      mmoveBind = mmove.bind(this);
      mupBind = mup.bind(this);
      document.addEventListener("mousemove", mmoveBind, {passive:false});
      document.addEventListener("touchmove", mmoveBind, {passive:false});
      document.addEventListener("mouseup", mupBind, false);
      document.addEventListener("touchend", mupBind, false);
      document.addEventListener("mouseleave", mupBind, false);
      document.addEventListener("touchleave", mupBind, false);
  }
  //Drag時の処理
  function mmove(e) {
      if(e.type === "mousemove") {
          event = e;
      } else {
          event = e.changedTouches[0];
      }
      e.preventDefault();
     if(document.elementFromPoint(event.clientX,event.clientY)){
      this.style.top = event.pageY - y + "px";
      this.style.left = event.pageX - x + "px";}
  }
  //クリック終了・手を離したときの処理
  function mup(e) {
      document.removeEventListener("mousemove", mmoveBind, {passive:false});
      document.removeEventListener("mouseup", mupBind, false);
      document.removeEventListener("touchmove", mmoveBind, {passive:false});
      document.removeEventListener("touchend", mupBind, false);
      document.removeEventListener("mouseleave", mupBind, false);
      document.removeEventListener("touchleave", mupBind, false);
  }
  //D&Dした要素の重なり調整
  function overlapSort(){
    elements.forEach( (elm,index) => {
     if(elm == this)
      {
        elements.splice(index,1);
        elements.push(this);
        elements[index].style.zIndex=1000+index;
      }
     else{ elm.style.zIndex=1000+index; }
    });
  }
}


まぁ参考にしたもなにもあまり変わっていませんが。基本的な考え方は同じですからね。移動先の座標を取得して対象要素にポジション指定と。↑の三つ目の記事で紹介されているコードを改造していったのでクラス名とかもそのままだったりします。移動をブラウザの表示範囲に限定したり移動した要素を最前面に持ってくるように変更したり…と細々変更してはいますが。動作確認しながらいじっていたら結構時間がかかりました。イベントリスナーの第三引数をfalseにしているだけでは何故かエラーがでます。ちゃんとpassive設定しないとpreventDefault()が上手く機能せずにエラーが。動作はするものの気持ち悪いので修正。よくわからないですがそういうものだと思っておく。他にもbind()を使用したときにイベントをremoveできるパターンとできないパターンがあるのもよくわかりませんでした。違いがないように思えたのですが。まぁ変数に入れておけばエラーが出ないということで全部変数に格納して使用。ちなみにtouchイベント系はPC版のIEとSafariでは未対応のようです。まぁPCユーザーはマウスを使用してください…ということで。でもエラー判定くらい入れて置いた方が良い気も?いや…タッチイベントが発生しないならエラーでないか。ブログでの動作確認のために↓にD&D要素を貼り付けておきます。実はそれがこの記事を書いた主目的だったりする。


BOX1
BOX2
BOX3


しかしどんどん脱線して全然先に進めない。知識が無さすぎて、やればやるほど気になるところが増えていくという泥沼状態。楽しめてはいるものの早く次に進みたいのだけどな。さて…ちゃんと動いてくれるだろうか。ちなみにD&Dやっぱり必要なし、との判断になりこのコードは結局使わなかったという…。

最新の投稿

このブログを検索

ブログ アーカイブ

自己紹介

ひきこもっていたらお爺さんになりました…嘘です。プロフ写真はFaceAppで老化したものです。本人はもう少しだけ若いです。
ブログ管理者は15年程ひきこもっている、長期ひきこもりのオッサンです。現在ブログは休止中。再開は未定です。 詳細なプロフィール

QooQ