Help us understand the problem. What is going on with this article?

Vuetify でなるべく疎結合になるように ref を使って Modal(モーダル)を実装する

More than 1 year has passed since last update.

Vuetify は Material デザインベースの Vue 用 Component ライブラリで、豊富なコンポーネントと丁寧なマニュアルが魅力だ。

Vuetify を使って Modal を実装する場合には v-dialogue component を使うといいと思う。(他にもっといいのあったら教えてください)

今回はこれをサンプルよりも疎結合になるように実装する方法について。ref を使う。

普通に実装する

サンプルを元に簡単に実装すると次のようになる。

https://codesandbox.io/embed/zn9o831624?module=%2Fsrc%2FApp.vue

App.vue
<template>
  <v-app>
  <div class="text-xs-center">
    <v-dialog
      v-model="dialog"
      width="500"
    >
      <v-btn
        slot="activator"
        color="red lighten-2"
        dark
      >
        Click Me
      </v-btn>

      <v-card>
        <v-card-title
          class="headline grey lighten-2"
          primary-title
        >
          Privacy Policy
        </v-card-title>

        <v-card-text>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
        </v-card-text>

        <v-divider></v-divider>

        <v-card-actions>
          <v-spacer></v-spacer>
          <v-btn
            color="primary"
            flat
            @click="dialog = false"
          >
            I accept
          </v-btn>
        </v-card-actions>
      </v-card>
    </v-dialog>
  </div>
  </v-app>
</template>

<script>
  export default {
    data () {
      return {
        dialog: false
      }
    }
  }
</script>

ただし上記例だと長すぎる。v-dialog 以下を別コンポーネントに切り出す

上記のように普通に実装すると、非常にコードが長くなる。v-dialog 以下を別コンポーネントに切り出したい。dialog.vue に切り出すとしよう。

ただしその際に問題になるのは、モーダルの開閉状態を制御する state である dialogApp.vue の中に残ってしまう。dialogdialog.vue でしか使わない state なので App.vue が持っているのはおかしい。これを dialogu.vue に任せることにしたい。

しかし、任せたら任せたで難しくなることが一つある。dialogu.vue に譲渡した dialog を、親コンポーネントである App.vue からどのように変更すればいいのか、という問題だ。親コンポーネントから、子コンポーネントの状態を変更したい場合は結構ある。具体的には、親コンポーネントで API からデータを fetch し、それが終わった時に子コンポーネントの modal を開く、といった場合だ。子コンポーネントにアクセスしなくてはいけない。

これを vuex で管理するのも一つの方法だが、この画面でしか使わない state を vuex で管理すべきでない。

今回は ref を使った実装を紹介する。

https://codesandbox.io/embed/n7l1n0q6rm

dialog.vue
<template>
  <v-app>
    <div class="parent">
      <button class="parent-button" @click="refToParentOpen">parent button</button>
      <app-dialogue ref="childDialogue"></app-dialogue>
    </div>
  </v-app>
</template>

<script>
  import appDialogue from './components/dialogue.vue'
  export default {
    components: {
      appDialogue
    },
    methods: {
      refToParentOpen(){
        this.$refs.childDialogue.open()
      }
    }
  }
</script>
<style scoped>
.parent {
  background: red
}

.parent-button {
  color: white;
  text-align: center;
  background: blue;
}
</style>

ポイントは、親コンポーネントで呼び出す「子コンポーネント」に対して、ref="name" という形で、参照を紐づけることだ。これによって、親コンポーネントからは this.$refs.name で参照することができる。あとは、this.$refs.name.methodName() という形で子コンポーネントの持つメソッドにアクセスできる。

注意点として、:ref="name" と書いてもうまく機能しないことをあげておく。なぜなら :refv-bind なので name という変数を参照することになってしまうからだ。もしこうかくのであれば、前もってこの変数を宣言しておく必要がある。

こうすることで、次のようにフェッチが終わって初めてモーダルを開く実装を親コンポーネントですることができる。

<script>
    methods: {
      refToParentOpen(){
        this.$refs.childDialogue.open()
      },
      async fetchData(){
        // まずフェッチする
        await axios.get(/api/endpoint)
     // フェッチが終わって初めてモーダルを開く 
        this.refToParentOpen()
      }
    }
</script>
superyusuke
最近は自分のサイトで技術情報を公開 https://uncle-javascript.com/article/ React 公式ドキュメントトップページの翻訳を担当。React.TypeScript Japan User Group 主宰 https://react-japan-user-grpup.connpass.com/
https://uncle-javascript.com/article/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした