0
0

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 3 years have passed since last update.

確認ダイアログ(confirm)でユーザー応答を待つ【Nuxt.js】

Posted at

はじめに

Webアプリを開発していて必ず欲しくなる確認ダイアログ。
image.png

window.confirm('こういうやつ!')

と書いてもいいのですが「デザインをこだわるために自作したい!」となって作成しました。

目標

作りたかったものは以下です。

  • テキストが変更できる
  • 前ページ共通で使いまわせる(各ページに配置などしない)
  • window.confirmのように処理を中断してtrue / falseを返せる

ダイアログを作る

ダイアログコンポーネントを作ります(HTML部分は適当&CSSは省略)。

DialogConfirm.vue
<template>
  <div v-if="isShown" class="dialog">
    <p>
      {{ text }}
    </p>
    <div class="dialog__buttons">
      <button @click="ok()">
        OK
      </button>
      <button @click="cancel()">
        Cancel
      </button>
    </div>
  </div>
</template>

<script lang="ts">
import Vue from 'vue';

type Data = {
  isShown: boolean,
  text: string,
  resolve: (v: boolean) => void
}

export default Vue.extend({
  data (): Data {
    return {
      isShown: false,
      text: '',
      resolve: () => {}
    };
  },

  methods: {
    confirm (text: string): Promise<boolean> {
      this.text = text;
      this.isShown = true;
      return new Promise((resolve: (v: boolean) => void) => {
        this.resolve = resolve;
      });
    },

    ok () {
      this.reset();
      this.resolve(true);
    },

    cancel () {
      this.reset();
      this.resolve(false);
    },

    reset () {
      this.isShown = false;
      this.text = '';
    }
  }
});
</script>

confirmメソッドでpromiseの解決をせず、コンポーネント内のdataにresolveを逃がしています。

confirm (text: string): Promise<boolean> {
  this.text = text;
  this.isShown = true;
  return new Promise((resolve: (v: boolean) => void) => {
      this.resolve = resolve;
  });
}

そしてダイアログ内のボタン押下でresolveしPromiseでラッピングしたbooleanを返します。

ok () {
  this.reset();
  this.resolve(true);
},

cancel () {
  this.reset();
  this.resolve(false);
}

Vueはrefsを使うことで子コンポーネントのメソッドを実行できます。
これを利用しダイアログコンポーネントのconfirmメソッドを叩くことを想定しています。

各ページから呼び出せるようにする

作成したダイアログコンポーネントを適当なlayoutsに配置し、呼び出せるようにします。

共通でメソッドを扱いたいため、メソッドをstoreに格納することにしました。
refsはVueオブジェクトから取るため、layoutscreatedstoreに格納します。
(もっといいやりかたありそう......)

default.vue
created () {
  this.$store.dispatch('setConfirmMethod', this.confirm);  // ストアに格納
},

methods: {
  confirm(text: string): Promise<boolean> {
    return (this.$refs.dialog as InstanceType<typeof DialogConfirm>).confirm(text);
  }
}

使いかた

これで適当なif文内でストアのconfirmを呼んでやると

async click() {
  if (await this.$store.state.confirm('こういうやつ!'))) {
    window.alert('confirm!')
  }
}

image.png

と出てきて確認してくれます。

おわりに

目標としていた3点を満たすコンポーネントを実装できました。

  • テキストが変更できる
  • window.confirmのように処理を中断してtrue / falseを返せる
  • 前ページ共通で使いまわせる(各ページに配置などしない)
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?