skysan's programming notebook

コーディングして思ったことなどを気ままに

続々・モーダルなコンポーネントのフォーカス管理(Nuxt.js版 2)

前回の反省

カスタムディレクティブで作ってみたが、ダイアログが埋め込んであるページに遷移する度にfocusinイベント登録が発生してしまう。

skysan87.hatenablog.com

今回やりたいこと

  • カスタムディレクティブをやめる。
  • 以下のサイトを参考にダイアログを動的に生成し、表示中のみfocusinイベントが動くようにする。

donzoko.jp

結果

  • SPAモードでのみ動作確認

ダイアログコンポーネントの実装

  • Dialog.vue
<template>
<div>
  <div tabindex="0" class="dummy"></div>

  <!-- モーダルダイアログの要素 -->
  <div>
    <input type="text" ref="modalComment" />
  </div>
  <div>
    <button @click="close">OK</button>
  </div>

  <div tabindex="0" class="dummy"></div>
</div>
</template>

<script>
export default {
  props: {
    parent: {
      type: Element,
      require: true
    }
  },
  mounted () {
    this.parent.appendChild(this.$el)
    this.$nextTick(() => {
      this.$el.focus()
      this.$refs.modalComment.focus()
      // ダイアログ生成時にイベント登録
      document.addEventListener('focusin', this.checkFocus, false)
    })
  },
  destroyed () {
    // ダイアログ破棄時にイベント解除
    document.removeEventListener('focusin', this.checkFocus, false)
    this.$el.remove()
  },
  methods: {
    close () {
      this.$emit('update', this.$refs.modalComment.value)
      this.$destroy()
    },
    checkFocus (ev) {
      if (ev.target !== null && ev.target.className === 'dummy') {
        this.$refs.modalComment.focus()
      }
    }
  }
}
</script>

ダイアログを呼ぶ方

import Vue from 'vue'
import dialog from '@/components/Dialog.vue'

const DialogController = Vue.extend(dialog)

export default {
  data () {
    return {
      dialog: null
    }
  },
  methods: {
   openDialog () {
      this.dialog = new DialogController({
        propsData: {
          parent: this.$root.$el //親要素は構成によって変わる
        }
      })
      this.dialog.$on('update', (comment) => {
         console.log(comment);
      })
      this.dialog.$mount()
    }
}

所感

・モーダル管理が楽になった。