はじめに
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オブジェクトから取るため、layouts
のcreated
でstore
に格納します。
(もっといいやりかたありそう......)
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!')
}
}
と出てきて確認してくれます。
おわりに
目標としていた3点を満たすコンポーネントを実装できました。
- テキストが変更できる
-
window.confirm
のように処理を中断してtrue / false
を返せる - 前ページ共通で使いまわせる(各ページに配置などしない)