zukucode
主にWEB関連の情報を技術メモとして発信しています。

Vue.js モーダルダイアログをプログラムから呼び出す

Vue.jsでモーダルダイアログをプログラムから呼び出す方法を紹介します。

以下のソースではVuetifyを使用していますが、CSSフレームワークにかかわらず考え方は同じです。

通常の方法

以下は、Vuetifyの公式ドキュメントで紹介している使用方法です。

変数dialogDialogの表示非表示を切り替えています。

<template>
  <v-dialog v-model="dialog">
  </v-dialog>
</template>
<script>
export default {
  data () {
    return {
      dialog: false,
    }
  }
}
</script>

この方法では、例えばアラートや確認メッセージなどをDialogで表示したい場合、各コンポーネント内にDialogを定義する必要があり、手間がかかります。

以下のように変数の切り替えではなく、プログラムから指定したコンポーネントを表示できるようにすれば、汎用的にDialogを使いまわすことができます。

// MyComponentは各Templateに配置する必要がない
this.$dialog({
  component: MyComponent
});

ミックスインの定義

Dialogで共通で使用するミックスインを定義します。

programmatic.js
export default {
  data() {
    return {
      show: false,
    };
  },
  created() {
    this.$mount();
    document.body.appendChild(this.$el);
    this.show = true;
  },
  methods: {
    close() {
      this.show = false;
      setTimeout(() => {
        if (document.body.contains(this.$el)) document.body.removeChild(this.$el);
        this.$destroy();
      }, 200);
    },
  },
};

モーダルコンポーネントの作成

次に、上記のミックスインを組み込んだコンポーネントを作成します。

<template>
  <v-dialog v-model="show" :max-width="400">
    <v-card>
      <v-card-title class="error white--text" primary-title>
        ダイアログ
      </v-card-title>
      <v-card-text class="pa-4">
        <p>ダイアログのテスト</p>
      </v-card-text>
      <v-divider></v-divider>
      <v-card-actions>
        <v-spacer></v-spacer>
        <v-btn @click="close">
          閉じる
        </v-btn>
      </v-card-actions>
    </v-card>
  </v-dialog>
</template>

<style lang="scss" scoped></style>

<script>
import programmatic from './programmatic';

export default {
  mixins: [programmatic],
};
</script>

$dialogファンクションを作成

次に以下のコマンドで呼び出せるように、汎用的な$dialogファンクションを定義します。

this.$dialog({
  component: MyComponent,
  propsData: parameter
});

ミックスインとして定義しても良いと思います。

async $dialog(payload) {
  const VM = Vue.extend(payload.component);
  new VM({
    parent: this,
    propsData: payload.propsData,
  });
},

呼び出し

以下のように定義します。

呼び出しボタンをクリックするとダイアログが起動することが確認できます。

<template>
  <v-btn @click="open">
    呼び出し
  </v-btn>
</template>

<script>
import MyComponent from './MyComponent';

export default {
  methods: {
    open() {
      this.$dialog({
        component: MyComponent,
        propsData: {
          test: 1
        }
      });
    }
  }
}
</script>

関連記事