LoadingOverlay 加载遮罩

盖在一块区域上的加载指示,稍作等待再显示。

本周新增

收藏 128 次,评论 32 条,新粉丝 12 位。

<script setup lang="ts">
  import { ref } from 'vue'
  import { Button, Card, LoadingOverlay, Stack, Text } from '@hina-ui/vue'

  const loading = ref(false)

  async function reload() {
    loading.value = true
    await new Promise(resolve => setTimeout(resolve, 1800))
    loading.value = false
  }
</script>

<template>
  <Stack gap="sm" align="start">
    <Card class="relative w-96">
      <Stack gap="xs">
        <Text weight="medium">本周新增</Text>
        <Text tone="muted" size="sm">收藏 128 次,评论 32 条,新粉丝 12 位。</Text>
      </Stack>
      <LoadingOverlay :visible="loading" text="正在刷新" />
    </Card>
    <Button variant="outline" tone="neutral" :disabled="loading" @click="reload">刷新</Button>
  </Stack>
</template>
vue

用法

import { LoadingOverlay } from '@hina-ui/vue'
ts

加载遮罩铺满最近的定位容器,把内容压淡并放上加载指示;把它放进带 relative 的容器里,用 visible 控制显隐。它一出现就挡住下面的交互,但要过一小段时间才真正显示出来,很快结束的请求不会闪一下。

这块内容在加载期间被压淡,也不能点击。

<script setup lang="ts">
  import { ref } from 'vue'
  import { Card, LoadingOverlay, Stack, Switch, Text } from '@hina-ui/vue'

  const loading = ref(true)
</script>

<template>
  <Stack gap="md" align="start">
    <Switch v-model="loading">显示遮罩</Switch>
    <Card class="relative w-96">
      <Text>这块内容在加载期间被压淡,也不能点击。</Text>
      <LoadingOverlay :visible="loading" />
    </Card>
  </Stack>
</template>
vue

示例

文字

text 在加载指示下方显示一行说明,同时作为指示的无障碍名称。

正在把草稿同步到云端。

<script setup lang="ts">
  import { Card, LoadingOverlay, Text } from '@hina-ui/vue'
</script>

<template>
  <Card class="relative h-40 w-96">
    <Text>正在把草稿同步到云端。</Text>
    <LoadingOverlay visible text="正在同步" size="lg" />
  </Card>
</template>
vue

延时与最短停留

delay 是 visible 变为真之后等多久再淡入,默认 300 毫秒,这段时间内撤掉它什么都不会出现;设为 0 立即显示,适合用户主动触发、明知要等的操作。minVisible 是显示之后至少停留多久,默认 300 毫秒,避免刚出现就消失的闪动;设为 0 则请求一结束就淡出。

默认延时下快请求看不到遮罩;打开「立即显示」后两种请求都会看到。

<script setup lang="ts">
  import { ref } from 'vue'
  import { Button, Card, Inline, LoadingOverlay, Stack, Switch, Text } from '@hina-ui/vue'

  const loading = ref(false)
  const immediate = ref(false)
  const result = ref('')

  async function request(ms: number) {
    loading.value = true
    result.value = ''
    await new Promise(resolve => setTimeout(resolve, ms))
    loading.value = false
    result.value = `${ms} 毫秒后返回`
  }
</script>

<template>
  <Stack gap="md" align="start">
    <Inline gap="md" align="center">
      <Button variant="outline" tone="neutral" :disabled="loading" @click="request(150)">
        快请求
      </Button>
      <Button variant="outline" tone="neutral" :disabled="loading" @click="request(1500)">
        慢请求
      </Button>
      <Switch v-model="immediate">立即显示</Switch>
    </Inline>
    <Card class="relative w-96">
      <Text>
        {{ result || '默认延时下快请求看不到遮罩;打开「立即显示」后两种请求都会看到。' }}
      </Text>
      <LoadingOverlay :visible="loading" :delay="immediate ? 0 : undefined" />
    </Card>
  </Stack>
</template>
vue

自定义内容

默认插槽替换薄面里的加载指示与文字,可以放品牌形象、进度说明等自己的内容;薄面、延时与挡住交互的行为不变。自定义内容里应当有 role="status" 或者等价的文字,辅助技术才知道这里在等待。

书架里的内容正在整理。

星见书音抱着书跑过来

书音正在整理书架,稍等一下。

<script setup lang="ts">
  import { Card, Image, LoadingOverlay, Stack, Text } from '@hina-ui/vue'
</script>

<template>
  <Card class="relative h-56 w-96">
    <Text>书架里的内容正在整理。</Text>
    <LoadingOverlay visible :delay="0">
      <Stack gap="xs" align="center" role="status">
        <Image
          src="/mascot/run.gif"
          alt="星见书音抱着书跑过来"
          :ratio="1"
          fit="contain"
          :skeleton="false"
          eager
          :lazy="false"
          class="size-28"
        />
        <Text size="sm" tone="muted">书音正在整理书架,稍等一下。</Text>
      </Stack>
    </LoadingOverlay>
  </Card>
</template>
vue

覆盖整个视口

fixed 让遮罩覆盖整个视口,用于整页级别的等待。

<script setup lang="ts">
  import { ref } from 'vue'
  import { Button, Image, LoadingOverlay, Stack, Text } from '@hina-ui/vue'

  const loading = ref(false)

  async function reload() {
    loading.value = true
    await new Promise(resolve => setTimeout(resolve, 2000))
    loading.value = false
  }
</script>

<template>
  <Button variant="outline" tone="neutral" @click="reload">覆盖整页两秒</Button>
  <LoadingOverlay :visible="loading" fixed>
    <Stack gap="xs" align="center" role="status">
      <Image
        src="/mascot/run.gif"
        alt="星见书音抱着书跑过来"
        :ratio="1"
        fit="contain"
        :skeleton="false"
        eager
        :lazy="false"
        class="size-32"
      />
      <Text size="sm" tone="muted">正在切换账号</Text>
    </Stack>
  </LoadingOverlay>
</template>
vue

行为

  • visible 变为真时立即挡住区域内的交互,等待 delay 后淡入;变为假时淡出并移除,显示未满 minVisible 则补足后再淡出。
  • 延时内撤掉不会闪现。
  • 遮罩不停止页面滚动,也不接管焦点;需要打断整页任务时用 Dialog 的锁定。

无障碍

  • 加载指示是 role="status",名称取自 text,没有时取语言包的「加载中」。
  • 显示的文字对辅助技术隐藏,避免与指示的名称重复播报。

API

Props

属性
类型
默认值
说明
visible
boolean
false
是否显示
text
string
—
指示下方的说明
fixed
boolean
false
是否覆盖整个视口
size
'sm' | 'md' | 'lg'
'md'
加载指示的尺寸
delay
number
300
显示前等待的毫秒数,0 立即显示
minVisible
number
300
显示后至少停留的毫秒数
class
string
—
追加至遮罩的类名

插槽

插槽
说明
default
薄面里的内容,默认是加载指示与 text