Admin 元件

Loading

讀取中指示。全螢幕或區塊 inline。

安裝

Terminal
pnpm dlx shadcn-vue add @admin/loading
import {  AdminLoading,  vAdminLoading,} from '@/components/admin/loading'

用法

<script setup lang="ts">import { ref } from 'vue'import { AdminButton } from '@/components/admin/button'import { AdminLoading } from '@/components/admin/loading'​const showFullscreen = ref(false)​function triggerFullscreen() {  showFullscreen.value = true  setTimeout(() => {    showFullscreen.value = false  }, 1500)}</script>​<template>  <div class="flex flex-col items-center gap-6">    <!-- 容器內 Loading(限制在展示框內) -->    <div class="relative h-32 w-64 overflow-hidden rounded-[8px] border">      <admin-loading mode="inline" />    </div>​    <!-- 全螢幕 Loading(1.5 秒後自動關閉) -->    <admin-button variant="outline" @click="triggerFullscreen">      觸發全螢幕 Loading(1.5s)    </admin-button>​    <teleport to="body">      <admin-loading v-if="showFullscreen" mode="fullscreen" />    </teleport>  </div></template>

場景

Inline 區塊 loading

<script setup lang="ts">import { ref } from 'vue'import { vAdminLoading } from '@/components/admin/loading/v-admin-loading'​const loading = ref(true)</script>​<template>  <div class="flex flex-col gap-3">    <button      class="self-start rounded-md border px-3 py-1 typo-content-medium"      type="button"      @click="loading = !loading"    >      切換 loading    </button>    <div      v-admin-loading="loading"      class="relative h-32 w-64 rounded-md border p-4 typo-content-medium"    >      被包住的內容區塊,inline mode loading 會以遮罩覆蓋此容器。    </div>  </div></template>

命令式全螢幕 loading

多個非同步請求共用一個全螢幕 loading:自行以 admin-loading 組裝;全域共享與計數由呼叫端決定。

下面這版用一個 ref-count counter:計數從 0 變 1 才顯示、從 1 變回 0 才隱藏,中間重疊的請求不會重複蓋上去。

<script setup lang="ts">import { ref } from 'vue'import { AdminButton } from '@/components/admin/button'import { AdminLoading } from '@/components/admin/loading'​const isLoading = ref(false)let pending = 0​function show() {  if (pending++ === 0) {    isLoading.value = true  }}​function hide() {  if (pending > 0 && --pending === 0) {    isLoading.value = false  }}​async function fetchData() {  show()  try {    await new Promise((resolve) => setTimeout(resolve, 1500))  } finally {    hide()  }}​async function fetchInParallel() {  await Promise.all([fetchData(), fetchData(), fetchData()])}</script>​<template>  <div class="flex flex-wrap gap-3">    <admin-button variant="outline" @click="fetchData"> 模擬單一請求 </admin-button>    <admin-button variant="outline" @click="fetchInParallel"> 模擬三個並行請求 </admin-button>    <admin-loading v-if="isLoading" mode="fullscreen" />  </div></template>

想讓多個元件共用同一份 loading 狀態,把 counter 包進 createSharedComposable(@vueuse/core)就行。要不要這樣做,看你。

搭配 useOverlay

如果你已經用 useOverlay 在統一管理 overlay,也可以讓它來掛 loading。只是它的 provider 會綁 open 和 after-leave,而 admin-loading 只是純展示元件、沒有這些 emit,所以得先包一層 wrapper 幫它補上:

loading-overlay-wrapper.vue
<script setup lang="ts">import { AdminLoading } from '@/components/admin/loading'​defineOptions({  name: 'loading-overlay-wrapper'})​defineProps<{  open?: boolean}>()​const emit = defineEmits<{  'update:open': [value: boolean]  close: []  afterLeave: []}>()</script>​<template>  <transition    enter-active-class="animate-in fade-in-0"    leave-active-class="animate-out fade-out-0"    appear    @after-leave="emit('afterLeave')"  >    <admin-loading v-if="open" mode="fullscreen" />  </transition></template>
<script setup lang="ts">import { AdminButton } from '@/components/admin/button'import { useOverlay } from '@/components/admin/overlay'import LoadingOverlayWrapper from './loading/loading-overlay-wrapper.vue'​const overlay = useOverlay()const loading = overlay.create(LoadingOverlayWrapper)​let pending = 0​function show() {  if (pending++ === 0) {    loading.open()  }}​function hide() {  if (pending > 0 && --pending === 0) {    loading.close()  }}​async function fetchData() {  show()  try {    await new Promise((resolve) => setTimeout(resolve, 1500))  } finally {    hide()  }}​async function fetchInParallel() {  await Promise.all([fetchData(), fetchData(), fetchData()])}</script>​<template>  <div class="flex flex-wrap gap-3">    <admin-button variant="outline" @click="fetchData"> 模擬單一請求 </admin-button>    <admin-button variant="outline" @click="fetchInParallel"> 模擬三個並行請求 </admin-button>  </div></template>

API 參考

組成

<template>  <admin-loading /></template>

admin-loading

Props

名稱型別預設值說明
mode"fullscreen" | "inline" | undefined—顯示模式變體(`fullscreen` / `inline`);未指定時預設為 `fullscreen`(fixed 全螢幕遮罩)
labelstring | undefined"載入中"顯示在 spinner 旁的文字標籤
classClassValue—根元素之自訂 class

Slots

名稱Bindings說明
default{ class: string; }—

更新紀錄

  • BREAKING refactor!: 移除 useLoading composable,改以 docs recipe 提供82c1ccd
  • fix: 修正 spinner 轉速加倍並抽出共用 overlay helperf05940a