search
LoginSignup
3

More than 1 year has passed since last update.

posted at

ドラッグで移動できるdialogタグをざっくりと作る

<dialog>タグとは

<dialog>: ダイアログ要素 - MDN web docs
https://developer.mozilla.org/ja/docs/Web/HTML/Element/dialog

まともに動くのはChromeとChromeベースのEdgeだけですね。
使いどころが難しいですが、社内システムとかで使う分には良いかなーって感じですね。

まずはダイアログを表示するコード

<dialog id="dialog">
  <h1>hello</h1>
</dialog>
<button id="show">show</button>

<script>
const showBtn = document.querySelector('#show');
const dlg = document.querySelector('#dialog');

showBtn.addEventListener('click', () => {
  dlg.showModal()
});
</script>

dialog要素はデフォルト非表示になります。
画面にはshowボタンしか表示されてませんね。

FireShot Capture 020 - Document - wsl.main.com.png

FireShot Capture 023 - Document - wsl.main.com.png

dialog要素はjsと共に使用され、dialog要素.showModal()で表示できます。

モーダルの枠線とかはデフォルトです。
モーダルの背景が若干灰色になってますね。
次はスタイルをいじってみましょう。

スタイルをいじる

<style>
/* モーダル */
dialog {
  border: none;
  border-radius: 10px;
}

/* モーダルの背景 */
dialog::backdrop {
  background-color: rgba(0, 0, 0, 0.5);
}
</style>

FireShot Capture 026 - Document - wsl.main.com.png

枠線を消して、角丸を入れてみました。
dialog::backdropはモーダルの背景の疑似要素です。半透明の黒を設定してみました。

ドラッグできるようにする

<style>
/* モーダル */
dialog {
  border: none;
  border-radius: 10px;
}

/* モーダルの背景 */
dialog::backdrop {
  background-color: rgba(0, 0, 0, 0.5);
}

/* モーダル内のテキストとかを選択不可にする */
dialog * {
  user-select: none;
}
</style>
<dialog id="dialog" draggable="true">
  <h1>hello</h1>
</dialog>
<button id="show">show</button>
<script>
const showBtn = document.querySelector('#show');
const dlg = document.querySelector('#dialog');

showBtn.addEventListener('click', () => {
  dlg.showModal()
});

/**
 * モーダルのどこをつかんで移動を開始したか保存する用
 */
let mouse = {
  x: 0,
  y: 0,
};

/**
 * モーダルのどこをつかんで移動を開始したか保存する
 * ドラッグ時についてくる半透明の要素を空のdivにして消す
 */
dlg.addEventListener('dragstart', evt => {
  mouse.y = dlg.offsetTop-evt.pageY;
  mouse.x = dlg.offsetLeft-evt.pageX;
  evt.dataTransfer.setDragImage(document.createElement('div'), 0, 0);
});

/**
 * ドラッグ時の座標を
 */
dlg.addEventListener('drag', evt => {
  if (evt.x === 0 && evt.y === 0) return;
  const top = evt.pageY + mouse.y;
  const left = evt.pageX + mouse.x;
  const right = window.outerWidth - evt.pageX;
  dlg.style.top = top + 'px';
  dlg.style.left = left + 'px';
  dlg.style.right = right + 'px';
});

/**
 * モーダルのどこをつかんで移動を開始したかをリセットする
 */
dlg.addEventListener('dragend', evt => {
  mouse = {
    x: 0,
    y: 0,
  };
});
</script>

FireShot Capture 029 - Document - wsl.main.com.png

こんな感じで移動できます。
ドラッグ開始したマウスの位置を設定しないと、マウスの位置がモーダルの左上となります。

また、dialog要素はデフォルトで

dialog {
  left: 0;
  right: 0;
  position: absolute;
  ...他
}

が入ってるのでleftとrightの両方を設定します。

evt.dataTransfer.setDragImage(document.createElement('div'), 0, 0);は無くても良いですが、半透明の要素がくっついてきます。

おしまい

ライブラリも何もなしにモーダル表示できるのは楽ですね。
ちなみにdialog要素form要素を内包して使うことが多いです。

<dialog>
  <form method="dialog">
    <button value="ok">OK</button>
  </form>
</dialog>
<script>
document.querySelector('dialog').addEventListener('close', () => {
  console.log(
    document.querySelector('dialog').returnValue
  );
});
</script>

method="dialog"を設定してsubmitするとモーダルが非表示になります。
OKのボタンが押されるとokという文字列をjsで受け取ることもできます。

皆さんも使ってみてはいかがでしょうか?

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
What you can do with signing up
3