Vue3のProviderパターンは、typescript環境は結構見かけたのだが
javascript環境でのはあまり見つからず、
試しに作ったローディングスピナーをメモとして残しておく
ちなみにLoadingSpinner.vueのCSSはタグだけ書いて
chatGPTにCSSだけいいように出力してもらったものなので注意
ディレクトリ構成
├ components
| └ LoadingSpinner
| ├ LoadingSpinner.vue
| └ loadingStore.js
├ App.vue
└ Chilled.vue
各ファイルのソース
LoadingSpinner.vue
<template>
<div v-if="store.isActive() === true">
<div id="loading-overlay" class="loading-overlay">
<div class="loading-spinner"></div>
</div>
</div>
</template>
<script setup>
import {inject} from 'vue'
import {key} from "./loadingStore.js"
const store = inject(key);
</script>
<style scoped>
/* ローディングスピナーとオーバーレイのスタイル */
.loading-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 999;
}
.loading-spinner {
display: inline-block;
width: 50px;
height: 50px;
border: 3px solid rgba(255, 255, 255, 0.3);
border-radius: 50%;
border-top-color: #fff;
animation: spin 1s ease-in-out infinite;
-webkit-animation: spin 1s ease-in-out infinite;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
@-webkit-keyframes spin {
to {
-webkit-transform: rotate(360deg);
}
}
</style>
loadingStore.js
import {ref} from 'vue'
const state = ref(false)
const hide = () => {
state.value = false;
};
const show = () => {
state.value = true;
};
const isActive = () => {
return state.value;
};
export const store = {
state,
hide,
show,
isActive
}
export const key = Symbol('LoadingSpinner')
App.vue
<template>
<div>
<Chilled></Chilled>
<LoadingSpinner/>
</div>
</template>
<script setup>
import {provide} from "vue";
import Chilled from './Chilled.vue'
import LoadingSpinner from './components/LoadingSpinner/LoadingSpinner.vue'
import {key, store} from './components/LoadingSpinner/loadingStore'
provide(key, store);
</script>
<style scoped>
</style>
Chilled.vue
<template>
<div>
<button @click="handleClick">ローディング</button>
</div>
</template>
<script setup>
import {inject} from 'vue';
import {key} from './components/LoadingSpinner/loadingStore'
const loadingStore = inject(key);
const sleep = (second) => new Promise(resolve => setTimeout(resolve, second * 1000))
const handleClick = async () => {
loadingStore.show();
await sleep(2); //2秒間だけsleep
loadingStore.hide();
}
defineExpose({
handleClick
});
</script>