こんにちは、”はふぃ”です。
Vueアプリケーションではv-if
やv-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が表示制御されている場合は、beforeMount
とbeforeDestoroy
を使うことで自身の表示状態を監視することができます。
< ChildComponent.vue >
<template> <div> <h3>Hello HAFILOG!</h3> </div> </template> <script> export default { mounted () { console.log('ChildComponentは表示状態です') }, beforeDestroy () { console.log('ChildComponentは非表示状態です') } } </script>


beforeMount
やbeforeDestroy
は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" /> …


少し複雑になってしまいましたが、やっていることは
mounted()
内でrootDiv要素がリサイズ(表示・非表示)された時にisShown
を変更する処理を設定isShown
の値をwatch
で監視し、変更されたらconsole.log
でログを表示
という流れです。
まとめ
基本的にはv-ifを使った出し分けが多いので、ライフサイクルフックを使った方法で良いと思います。しかし、頻繁に表示を変更する場合はv-showを利用した方が良いとされているので、その場合にresize-observer-polyfillを使った方法を覚えておくと便利かもしれません。
参考
今回のコードはgithubで公開中なので参考にしてみてください!↓
https://github.com/hafilog/vue-sample/tree/master/components/pages/sample