vue-loading-overlay vs vue-spinner
Vue.jsアプリケーションにおけるローディングインジケーターの実装
vue-loading-overlayvue-spinner

Vue.jsアプリケーションにおけるローディングインジケーターの実装

vue-loading-overlayvue-spinner は、どちらも Vue.js アプリケーションでローディング状態を視覚的に表現するためのコンポーネントライブラリです。vue-loading-overlay は、画面全体または特定の要素に半透明のオーバーレイを重ねてスピナーを表示する方式を採用しており、ユーザー操作を一時的にブロックしながら読み込み中であることを伝える用途に適しています。一方、vue-spinner は軽量な CSS ベースのスピナーアニメーションコンポーネント群を提供し、UI の任意の場所にシンプルな回転アニメーションを埋め込むことに特化しています。両者は目的が似ていますが、実装アプローチや使用シーンに明確な違いがあります。

npmのダウンロードトレンド

3 年

GitHub Starsランキング

統計詳細

パッケージ
ダウンロード数
Stars
サイズ
Issues
公開日時
ライセンス
vue-loading-overlay01,27057.5 kB42年前MIT
vue-spinner01,81098.8 kB181ヶ月前MIT

vue-loading-overlay vs vue-spinner: ローディングUIの実装戦略を比較

Vue.js アプリケーションで非同期処理中にユーザーにフィードバックを提供する際、vue-loading-overlayvue-spinner はよく検討される選択肢です。しかし、これらは根本的に異なるアプローチを取っており、用途によって適切な方が変わります。以下では、実際の開発シーンを想定して技術的な違いを掘り下げます。

🛑 ユーザー操作のブロッキング:オーバーレイ有り vs 無し

vue-loading-overlay は、ローディング時に半透明のオーバーレイレイヤーを要素上に重ねることで、その領域のユーザー操作を物理的にブロックします。これは、意図しない再送信や状態の不整合を防ぐのに効果的です。

<!-- vue-loading-overlay の基本使用法 -->
<template>
  <div>
    <loading :active.sync="isLoading" :is-full-page="false">
      <span>データ取得中...</span>
    </loading>
    <button @click="fetchData">データ取得</button>
  </div>
</template>

<script>
import Loading from 'vue-loading-overlay';
import 'vue-loading-overlay/dist/vue-loading.css';

export default {
  components: { Loading },
  data() {
    return { isLoading: false };
  },
  methods: {
    async fetchData() {
      this.isLoading = true;
      await apiCall();
      this.isLoading = false;
    }
  }
};
</script>

vue-spinner は純粋な視覚的インジケーターであり、オーバーレイ機能を持ちません。ユーザーはローディング中でもボタンをクリックしたり入力したりできます。そのため、操作の多重実行を防ぐには別途ロジックが必要です。

<!-- vue-spinner の基本使用法 -->
<template>
  <div>
    <clip-loader v-if="isLoading" :loading="isLoading" size="30px" color="#3498db" />
    <button @click="fetchData" :disabled="isLoading">データ取得</button>
  </div>
</template>

<script>
import { ClipLoader } from 'vue-spinner';

export default {
  components: { ClipLoader },
  data() {
    return { isLoading: false };
  },
  methods: {
    async fetchData() {
      if (this.isLoading) return; // 二重送信防止のための手動チェック
      this.isLoading = true;
      await apiCall();
      this.isLoading = false;
    }
  }
};
</script>

🎨 カスタマイズ性とデザイン制御

vue-loading-overlay は、オーバーレイの背景色、不透明度、z-index、スピナータイプなどを props で細かく制御できます。また、スロットを使ってカスタムメッセージや独自のスピナーを挿入することも可能です。

<loading
  :active.sync="isLoading"
  :background-color="'#f0f0f0'"
  :opacity="0.8"
  :z-index="9999"
  loader="dots"
/>

vue-spinner は各スピナーコンポーネント(例: PulseLoader, BarLoader)ごとに色・サイズ・速度などのスタイルを調整できますが、オーバーレイ関連の設定は一切ありません。デザインはあくまで「スピナーそのもの」に限定されます。

<bar-loader
  :loading="isLoading"
  :color="'#e74c3c'"
  :height="6"
  :width="100"
/>

📱 レスポンシブ対応と配置の柔軟性

vue-loading-overlayis-full-page prop により、画面全体にオーバーレイを展開するか、親要素内に限定するかを切り替えられます。これにより、グローバルローディングとローカルローディングの両方に対応可能です。

// 画面全体に表示
<loading :active.sync="isLoading" :is-full-page="true" />

// 親要素内のみ
<div style="position: relative">
  <loading :active.sync="isLoading" :is-full-page="false" />
</div>

vue-spinner は通常の Vue コンポーネントとして配置されるため、CSS で自由に配置できますが、画面全体への表示には追加のスタイリング(例: position: fixed; top: 0; left: 0; width: 100vw; height: 100vh)が必要です。この点で、即座にフルスクリーンローディングを実現したい場合は手間が増えます。

🔧 Vue 3 との互換性

vue-loading-overlay は公式に Vue 3 をサポートしており、Composition API との併用も問題ありません。インストール後、createApp().use(LoadingPlugin) のようにプラグインとして登録可能です。

// Vue 3 での使用例
import { createApp } from 'vue';
import Loading from 'vue-loading-overlay';
import 'vue-loading-overlay/dist/css/index.css';

const app = createApp(App);
app.component('Loading', Loading);

vue-spinner は主に Vue 2 向けに設計されており、Vue 3 での動作はコミュニティによる非公式な対応に依存する場合があります。npm ページや GitHub リポジトリには Vue 3 対応の明確な記述がなく、新規プロジェクトで採用する際は事前の検証が必須です。

💡 選定のポイントまとめ

  • 操作をブロックしたいvue-loading-overlay
  • 軽量でシンプルなスピナーが欲しいvue-spinner
  • Vue 3 プロジェクトvue-loading-overlay を推奨(vue-spinner は互換性要確認)
  • フルスクリーンローディングが必要vue-loading-overlayis-full-page が便利
  • ローディング中も操作を許可したいvue-spinner + 手動の状態管理

最終的には、ユーザー体験の設計方針 — ローディング中に操作を許容するか否か — が選択の分かれ目になります。

選び方: vue-loading-overlay vs vue-spinner

  • vue-loading-overlay:

    vue-loading-overlay は、ユーザーの操作を一時的に無効化しつつ、モーダル的なローディング状態を表示したい場合に最適です。特にフォーム送信中や非同期処理中に画面全体または特定のコンテナ要素を覆ってフィードバックを提供する必要があるケースに向いています。Vue 2/3 の両方に対応しており、z-index や背景色、スピナータイプなどのカスタマイズが容易です。

  • vue-spinner:

    vue-spinner は、軽量で単純なスピナーアニメーションを UI の一部として埋め込みたい場合に適しています。オーバーレイ機能は持たず、純粋に視覚的なローディングインジケーターとして動作します。バンドルサイズを極力抑えたい軽量アプリや、ローディング状態でもユーザー操作を許容したい場面で有効です。ただし、Vue 3 での公式サポートは確認されておらず、新規プロジェクトでは互換性を慎重に検証する必要があります。

vue-loading-overlay のREADME

Vue Loading Overlay Component

downloads jsdelivr npm-version github-tag build license TypeScript

Vue.js component for full screen loading indicator

Demo or JSFiddle

Version matrix

Vue.js versionPackage versionBranch
2.x3.x3.x
3.x6.xmain

Installation

npm install vue-loading-overlay@^6.0 

Usage

As component


<template>
    <div class="vl-parent">
        <loading v-model:active="isLoading"
                 :can-cancel="true"
                 :on-cancel="onCancel"
                 :is-full-page="fullPage"/>

        <label><input type="checkbox" v-model="fullPage">Full page?</label>
        <button @click.prevent="doAjax">fetch Data</button>
    </div>
</template>

<script>
    import Loading from 'vue-loading-overlay';
    import 'vue-loading-overlay/dist/css/index.css';

    export default {
        data() {
            return {
                isLoading: false,
                fullPage: true
            }
        },
        components: {
            Loading
        },
        methods: {
            doAjax() {
                this.isLoading = true;
                // simulate AJAX
                setTimeout(() => {
                    this.isLoading = false
                }, 5000)
            },
            onCancel() {
                console.log('User cancelled the loader.')
            }
        }
    }
</script>

As plugin

Initialise the plugin in your app

import {createApp} from 'vue';
import {LoadingPlugin} from 'vue-loading-overlay';
import 'vue-loading-overlay/dist/css/index.css';
// Your app initialization logic goes here
const app = createApp({});
app.use(LoadingPlugin);
app.mount('#app');

Then use the plugin in your components


<template>
    <form @submit.prevent="submit"
          class="vl-parent"
          ref="formContainer">
        <!-- your form inputs goes here-->
        <label><input type="checkbox" v-model="fullPage">Full page?</label>
        <button type="submit">Login</button>
    </form>
</template>

<script>
    export default {
        data() {
            return {
                fullPage: false
            }
        },
        methods: {
            submit() {
                let loader = this.$loading.show({
                    // Optional parameters
                    container: this.fullPage ? null : this.$refs.formContainer,
                    canCancel: true,
                    onCancel: this.onCancel,
                });
                // simulate AJAX
                setTimeout(() => {
                    loader.hide()
                }, 5000)
            },
            onCancel() {
                console.log('User cancelled the loader.')
            }
        }
    }
</script>

or same with Composition API

<script setup>
    import {ref, inject} from 'vue'
    import {useLoading} from 'vue-loading-overlay'
    
    const $loading = useLoading({
        // options
    });
    // or use inject without importing useLoading
    // const $loading =  inject('$loading')

    const fullPage = ref(false)

    const submit = () => {
        const loader = $loading.show({
            // Optional parameters
        });
        // simulate AJAX
        setTimeout(() => {
            loader.hide()
        }, 5000)
    }
</script>

Available props

The component accepts these props:

AttributeTypeDefaultDescription
activeBooleanfalseShow loading by default when true, use it as v-model:active
can-cancelBooleanfalseAllow user to cancel by pressing ESC or clicking outside
on-cancelFunction()=>{}Do something upon cancel, works in conjunction with can-cancel
is-full-pageBooleantrueWhen false; limit loader to its container^
transitionStringfadeTransition name
colorString#000Customize the color of loading icon
heightNumber*Customize the height of loading icon
widthNumber*Customize the width of loading icon
loaderStringspinnerName of icon shape you want use as loader, spinner or dots or bars
background-colorString#fffCustomize the overlay background color
opacityNumber0.5Customize the overlay background opacity
z-indexNumber9999Customize the overlay z-index
enforce-focusBooleantrueForce focus on loader
lock-scrollBooleanfalseFreeze the scrolling during full screen loader
  • ^When is-full-page is set to false, the container element should be positioned as position: relative. You can use CSS helper class vl-parent.
  • *The default height and width values may vary based on the loader prop value

Available slots

The component accepts these slots:

  • default - Replace the animated icon with yours
  • before - Place anything before the animated icon, you may need to style this.
  • after - Place anything after the animated icon, you may need to style this.

API methods

this.$loading.show(?propsData,?slots)

import {h} from 'vue';

let loader = this.$loading.show({
    // Pass props by their camelCased names
    container: this.$refs.loadingContainer,
    canCancel: true, // default false
    onCancel: this.yourCallbackMethod,
    color: '#000000',
    loader: 'spinner',
    width: 64,
    height: 64,
    backgroundColor: '#ffffff',
    opacity: 0.5,
    zIndex: 999,
}, {
    // Pass slots by their names
    default: h('your-custom-loader-component-name'),
});
// hide loader whenever you want
loader.hide();

Global configs

You can set props and slots for all future instances when using as plugin

app.use(LoadingPlugin, {
    // props
    color: 'red'
}, {
    // slots
})

Further you can override any prop or slot when creating new instances

let loader = this.$loading.show({
    color: 'blue'
}, {
    // override slots
});

Use directly in browser (with CDN)

<!-- Vue js -->
<script src="https://cdn.jsdelivr.net/npm/vue@3.3"></script>
<!-- Lastly add this package -->
<script src="https://cdn.jsdelivr.net/npm/vue-loading-overlay@6"></script>
<link href="https://cdn.jsdelivr.net/npm/vue-loading-overlay@6/dist/css/index.css" rel="stylesheet">
<!-- Init the plugin and component-->
<script>
    const app = Vue.createApp({});
    app.use(VueLoading.LoadingPlugin);
    app.component('loading', VueLoading.Component)
    app.mount('#app')
</script>

Run examples on your localhost

  • Clone this repo
  • Make sure you have node-js >=20.11 and pnpm >=8.x pre-installed
  • Install dependencies pnpm install
  • Run webpack dev server npm start
  • This should open the demo page in your default web browser

Testing

  • This package is using Jest and vue-test-utils for testing.
  • Execute tests with this command npm test

License

MIT License