26
21

More than 5 years have passed since last update.

Vue.jsで独自の確認ダイアログ(confirm)をつくる

Last updated at Posted at 2019-01-21

WEBアプリケーションでユーザに意思を確認したいときはwindow.confirmが使われるかと思います。
しかし、window.confirm系で出せるダイアログはブラウザ依存なので、独自のスタイルを当てることができません。
無機質な確認ダイアログだと統一性がなくて悲しい気持ちになりますよね。

そこでVue.jsで独自の確認ダイアログを作成してみたいと思います。

実装方針

簡単に実装方針をまとめます。

  • メソッドはVueのグローバルミックスインとする
    • 引数は表示するメッセージ
    • 返り値は非同期で受け取る
      • メソッドの結果はPromise<boolean>
  • Vuetifyのv-dialogを使用する
    • スタイルやアニメーションを考えるのが面倒なので
  • コンポーネントは呼び出し毎に作成・破棄する
    • 常に用意しておくことはしない
    • bodyの末尾に追加

実装

上記の観点から確認ダイアログを実装します。

確認ダイアログのコンポーネント

createdのタイミングでbodyに追加をしています。

vue-class-componentを使用しています。

Confirm.vue
<template lang="pug">
v-dialog(v-model="isActive" persistent max-width="30%")
  v-card
    v-card-text {{ message }}
    v-card-actions.pt-0
      v-spacer
      v-btn(
        color="primary"
        depressed
        @click.native="ok"
      ) OK
      v-btn(
        outline
        @click.native="cancel"
      ) キャンセル
</template>

<script lang="ts">
import Vue from 'vue';
import Component from 'vue-class-component';
import { Prop } from 'vue-property-decorator';

@Component
export default class extends Vue {

    isActive = false;

    @Prop() message: string;
    @Prop() success: () => void;
    @Prop() failure: () => void;

    created() {
        const el = document.createElement('div');
        document.getElementsByTagName('body')[0].appendChild(el);
        this.$mount(el);

        this.isActive = true;
    }

    ok() {
        this.success();
        this.destroy();
    }

    cancel() {
        this.failure();
        this.destroy();
    }

    destroy() {
        this.isActive = false;

        // 即座にdomを削除するとtransitionする前に消えてしまうので、200ms待つ
        setTimeout(() => {
            this.$el.parentNode.removeChild(this.$el);
            this.$destroy();
        }, 200);
    }

}
</script>

インストーラ

次にミックスインをするインストーラです。
TypeScriptを想定しているので、定義も書いておきます。

ConfirmMixin.ts
import { VueConstructor } from 'vue';
import Confirm from '/path/to/Confirm.vue';

declare module 'vue/types/vue' {
    interface Vue {
        $confirm(message: string): Promise<boolean>;
    }
}

export default class {
  static install(Vue: VueConstructor) {
    Vue.mixin({
      methods: {
        $confirm: (message: string) => {
          return new Promise((resolve) => {
            new Confirm({
              propsData: {
                message,
                success: () => resolve(true),
                failure: () => resolve(false),
              },
            });
          });
        },
      },
    });
  }
}

利用部分

最後に実際にインストールする部分。
通常のライブラリと同様にVue.useを呼ぶだけです。

index.ts
import Vue from 'vue';
import Vuetify from 'vuetify';
import ConfirmMixin from '/path/to/ConfirmMixin';

Vue.use(Vuetify);
Vue.use(ConfirmMixin);

呼び出すとき

実際にアプリケーションの中で呼び出す時はこんな感じです。

<template lang="pug">
v-layout(column fill-height)
  v-btn(@click="hoge") hogehogeする
</template>

<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";

@Component
export default class extends Vue {
  async hoge() {
    const result = await this.$confirm("本当にhogehogeする?");
    console.log(result)
  }
}
</script>

動かしてみた

実際に動作してみるとこんな感じになります。

confirm.gif

まとめ

Vue.js + Vuetifyを使って独自の確認ダイアログを作成してみました。
ここまで作成してしまえば、少し手を加えるだけでアラートやエラーダイアログも作成できますし、そのほかの情報も表示できるので、いろんな使い方を試してみてください。

26
21
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
26
21