こんにちは、”はふぃ”です。

Vueアプリケーションではv-ifv-showを使ってコンポーネントの表示制御を行うと思います。

v-if

参考:https://jp.vuejs.org/v2/guide/conditional.html#v-if

v-show

参考:https://jp.vuejs.org/v2/guide/conditional.html#v-show

その際に対象のコンポーネントが表示された時に特定の処理を行うことは多いと思います。

そこで今回は、自身や子コンポーネントの表示状態を監視する方法について説明します。

親コンポーネントで子コンポーネントの表示状態を監視する

子コンポーネントが表示されているかどうかについては、親コンポーネントからは変数を使って容易に監視することができます。

例えば、監視したいコンポーネントをChildComponent.vueとし、それを親コンポーネントであるParentComponent.vueで監視する場合は以下のようになります。

< ChildComponent.vue >

<template>
  <div>
    <h3>Hello HAFILOG!</h3>
  </div>
</template>

< ParentComponent.vue >

<template>
  <div>
    <child-component v-if="isShownChildComponent" />

    <button @click.prevent="onClickBtn">クリック</button>
    <p>childComponentは{{ isShownChildComponent ? '表示' : '非表示' }}状態です</p>
  </div>
</template>

<script>
import ChildComponent from './ChildComponent'

export default {
  components: {
    ChildComponent
  },
  data () {
    return {
      isShownChildComponent: false
    }
  },
  methods: {
    onClickBtn () {
      this.isShownChildComponent = !this.isShownChildComponent
    }
  }
}
</script>

「クリック」と書かれたボタンを押してChildComponentの表示を切り替える簡単なプログラムですが、isShownChildComponentを使ってコンポーネントの表示状態を監視し、「表示」と「非表示」の文字を切り替えることができています。

子コンポーネントで自身の表示状態を監視する

今度は子コンポーネントであるChildComponentで自身の表示状態を監視する場合についてです。

v-ifで表示制御されている場合

上記のプログラムのようにv-ifを使ってChildComponentが表示制御されている場合は、beforeMountbeforeDestoroyを使うことで自身の表示状態を監視することができます。

< ChildComponent.vue >

<template>
  <div>
    <h3>Hello HAFILOG!</h3>
  </div>
</template>

<script>
export default {
  mounted () {
    console.log('ChildComponentは表示状態です')
  },
  beforeDestroy () {
    console.log('ChildComponentは非表示状態です')
  }
}
</script>

beforeMountbeforeDestroyはVue.jsのライフサイクルフックと呼ばれるものです。beforeMountならインスタンスがマウントされる前、beforeDestroyならインスタンスが破棄される前に処理を実行することができます。

v-ifでは、状態が変化するたびに対象のコンポーネントを構築・破棄するのでこれらを利用して自身の表示状態を監視することが可能です。

インスタンスライフサイクルフック

参考:https://jp.vuejs.org/v2/guide/instance.html#%E3%82%A4%E3%83%B3%E3%82%B9%E3%82%BF%E3%83%B3%E3%82%B9%E3%83%A9%E3%82%A4%E3%83%95%E3%82%B5%E3%82%A4%E3%82%AF%E3%83%AB%E3%83%95%E3%83%83%E3%82%AF

v-showで表示制御されている場合

今度はv-showで表示制御されている場合を考えます。

v-showではv-ifと違って、cssのdisplay: noneを使って表示制御をしておりコンポーネントは常に存在する状態なので、先ほどのライフサイクルフックを利用した方法は使うことができません

そこでresize-observer-polyfillというnpmパッケージを利用します。

$ npm install resize-observer-polyfill --save-dev

このパッケージはその名の通り要素のリサイズを検知するため、v-showによる表示制御でも対象コンポーネントを監視することが可能となります。

< ChildComponent.vue >

<template>
  <div ref="rootDiv">
    <h3>Hello HAFILOG!</h3>
  </div>
</template>

<script>
import ResizeObserver from 'resize-observer-polyfill'

export default {
  data () {
    return {
      observer: null,
      isShown: false
    }
  },
  watch: {
    isShown (val) {
      console.log(`ChildComponentは${this.isShown ? '表示' : '非表示'}状態です`)
    }
  },
  mounted () {
    this.observer = new ResizeObserver((entries) => {
      this.isShown = !this.isShown
    })
    this.observer.observe(this.$refs.rootDiv)
  },
  beforeDestroy () {
    this.observer.disconnect(this.$refs.rootDiv)
  }
}
</script>

< ParentComponent.vue >

<template>
  <div>
    <child-component v-show="isShownChildComponent" />
…

少し複雑になってしまいましたが、やっていることは

  1. mounted()内でrootDiv要素がリサイズ(表示・非表示)された時にisShownを変更する処理を設定
  2. isShownの値をwatchで監視し、変更されたらconsole.logでログを表示

という流れです。

まとめ

基本的にはv-ifを使った出し分けが多いので、ライフサイクルフックを使った方法で良いと思います。しかし、頻繁に表示を変更する場合はv-showを利用した方が良いとされているので、その場合にresize-observer-polyfillを使った方法を覚えておくと便利かもしれません。

参考

今回のコードはgithubで公開中なので参考にしてみてください!↓

https://github.com/hafilog/vue-sample/tree/master/components/pages/sample

投稿者: はふぃ

若手のWEBフロントエンジニア。最近はバレーボールにハマってます!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

CAPTCHA