[Vue3] 命令型コンポーネントを作成する方法
開発中、操作状態を表示するために全画面ローディングコンポーネント(例:フルスクリーンのローディング)が必要になることがよくあります。以下はシンプルな FullscreenLoading.vue コンポーネントの例です:
Loading...
一般的には、ページのテンプレートにこのコンポーネントを使用し、変数でその表示・非表示を制御します:
<template>
<FullscreenLoading v-if="showLoading" />
<div class="wrapper">
<button @click="clickHandler">Show Loading</button>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import FullscreenLoading from './components/FullscreenLoading.vue'
const showLoading = ref(false)
const clickHandler = () => {
showLoading.value = true
setTimeout(() => {
showLoading.value = false
}, 2000)
}
</script>
この方法は分かりやすいですが、複数のページで同じローディングロジックが必要な場合、各ページでコンポーネントをインポートし、状態を管理する必要のため、コードがたくさん重複してしまいます。
これを解決するために、ローディングロジックを命令型コンポーネントとしてカプセル化し、インポートや状態管理なしに簡単に呼び出せるようにします。
命令型コンポーネントを作成する
Vue の createApp メソッドを使用して、動的にコンポーネントインスタンスを作成し、DOM にマウントします:
import FullscreenLoading from '@/components/FullscreenLoading.vue'
import { createApp } from 'vue'
export function showLoading() {
const app = createApp(FullscreenLoading)
const container = document.createElement('div')
app.mount(container)
document.body.appendChild(container)
return {
close: () => {
app.unmount()
document.body.removeChild(container)
},
}
}
コードの説明
- コンポーネントインスタンスを動的に作成:
createAppを使用して、FullscreenLoading コンポーネントのインスタンスを作成します。 - DOM にマウント:div コンテナを作成し、そのコンポーネントインスタンスをマウントし、body に追加します。
- クローズ関数:
close関数を返し、コンポーネントのアンマウントと DOM のクリーンアップを行います。これにより、メモリリークを防ぎます。
命令型コンポーネントを使用する
showLoading 関数を使用すると、コンポーネントや状態を明示的にインポートすることなく、全画面ローディングを簡単に表示できます:
<template>
<div class="wrapper">
<button @click="clickHandler">Show Loading</button>
</div>
</template>
<script setup lang="ts">
import { showLoading } from './utils/loading.util'
const clickHandler = () => {
const { close } = showLoading()
setTimeout(() => {
close()
}, 2000)
}
</script>
showLoading を呼び出すと、ローディングコンポーネントが自動的に表示されます。閉じる場合は、showLoading が返す close 関数を呼び出します。この方法はシンプルで、複数ページでのコードの重複を回避できます。
まとめ
ローディングロジックを命令型コンポーネントとしてカプセル化することで、全画面ローディングインジケーターをより簡単に表示・非表示にできます。showLoading を呼び出すだけでローディングを表示でき、close 関数で非表示にできます。このカプセル化により、テンプレートの複雑さを軽減し、コンポーネントの再利用性が向上します。同様のシナリオでの動的 UI 操作に非常に適しています。
この内容が参考になれば幸いです!