4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

useConfirmDialogで確認ダイアログをスマートに実装する

Last updated at Posted at 2023-06-12

前置き

今回はVue3で確認ダイアログを実装するのにおすすめのフックを紹介します。

素直な実装例

コンポーネント全体

<template>
  <div>
    <button :disabled="showDialog" @click="onClick">
      確認
    </button>
    <div v-if="showDialog">
      ダイアログ表示
      <button @click="onConfirm">
        OK
      </button>
      <button @click="onCancel">
        Cancel
      </button>
    </div>
  </div>
</template>

<script lang="ts">
import { defineComponent, ref } from 'vue';

export default defineComponent({
  setup() {
    const showDialog = ref(false);
    function onClick() {
      showDialog.value = true;
    }

    function onConfirm() {
      showDialog.value = false;

      // 確認後処理
    }

    function onCancel() {
      showDialog.value = false;
    }

    return {
      showDialog,
      onClick,
      onConfirm,
      onCancel,
    };
  },
});
</script>

確認ダイアログの制御部分をピックアップ

    const showDialog = ref(false);
    function onClick() {
      showDialog.value = true;
    }

    function onConfirm() {
      showDialog.value = false;

      // 確認後処理
    }

    function onCancel() {
      showDialog.value = false;
    }

ダイアログ制御のためにだいたい4つの定義をするのではないでしょうか?

  • showDialog: 表示制御のためのフラグ
  • onClick: ボタンクリック
  • onConfirm: OKが押されたときのメソッド
  • onCancel: キャンセルが押されたときのメソッド

useConfirmDialogを使ったスマートな実装例

    const dialog = useConfirmDialog();
    async function onClick() {
      const { isCanceled } = await dialog.reveal();

      if (isCanceled) return;

      // 確認後処理
    }

これだけです。
独自の確認ダイアログでもwindow.confirmのように1行で書けます。
ボタンを押してからメインの処理まで一つの関数にまとまり可読性も良いです。

これだけ知っておけば使えるプロパティ/メソッド

プロパティ/メソッド 説明
reveal (data?: RevealData) => Promise<UseConfirmDialogRevealResult<ConfirmData, CancelData>> 確認ダイアログを開始するメソッド。
confirm (data?: ConfirmData) => void OKでダイアログを終了する
cancel (data?: CancelData) => void キャンセルでダイアログを終了する
isRevealed ComputedRef<boolean> 確認ダイアログ表示中の状態

コンポーネント全体

<template>
  <div>
    <button :disabled="dialog.isRevealed.value" @click="onClick">
      確認
    </button>
    <div v-if="dialog.isRevealed.value">
      ダイアログ表示
      <button @click="dialog.confirm">
        OK
      </button>
      <button @click="dialog.cancel">
        Cancel
      </button>
    </div>
  </div>
</template>

<script lang="ts">
import { useConfirmDialog } from '@vueuse/core';
import { defineComponent } from 'vue';

export default defineComponent({
  setup() {
    const dialog = useConfirmDialog();
    async function onClick() {
      const { isCanceled } = await dialog.reveal();

      if (isCanceled) return;

      // 確認後処理
    }

    return {
      dialog,
      onClick,
    };
  },
});
</script>

私の実用例

私はさらにwindow.confirmのように使えるようにメッセージも渡せる機能を作りました。

<template>
  <div>
    <button :disabled="dialog.isRevealed.value" @click="onClick">
      確認
    </button>
    <MessageDialog :dialog="dialog"/>
  </div>
</template>

<script lang="ts">
import { useMessageDialog } from '@/hooks/message_dialog.ts';
import { defineComponent } from 'vue';

export default defineComponent({
  setup() {
    const dialog = useMessageDialog();
    async function onClick() {
      const { isCanceled } = await dialog.confirm('メッセージ');

      if (isCanceled) return;

      // 確認後処理
    }

    return {
      dialog,
      onClick,
    };
  },
});
</script>

ポイントを紹介します。

  • useMessageDialogフック: useConfirmDialogをラップして、ダイアログに表示するメッセージデータを持てるようにしたカスタムフックです。
  • confirmメソッド: revealメソッドをラップして、独自のメッセージを渡せるようにします。
  • MessageDialogコンポーネント: useMessageDialogとセットで利用するコンポーネントです。メッセージデータを取り出して表示し、OKボタンとキャンセルボタンを持ちます。
4
1
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
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?