Skip to content

加载条 LoadingBar ​

赞助

加载进度条

何时使用 ​

  • 加载数据时,显示加载条,提示用户正在加载
  • 显示整个页面加载的进度
  • 显示上传图片或文件的上传进度

提示

LoadingBar 推荐在组件 setup 内通过 useLoadingBar() 调用,使用前需在应用根节点放置一次 <LoadingBarProvider>。
如果你想在 setup 外使用(例如 axios 拦截器、路由守卫、Pinia action 等),请参考文档末尾的 在 setup 外使用。

使用方式 ​

调用方式API适用位置
组件树内调用
推荐
useLoadingBar()组件 setup 内,需外层存在 <LoadingBarProvider>
脱离组件树调用
无需 LoadingBarProvider
createDiscreteApi()任意位置(axios 拦截器、路由守卫、Pinia action 等)

组件树内使用:useLoadingBar()
推荐
​


适用于组件内部调用:先在应用根节点放置一次 <LoadingBarProvider>,之后任意层级组件均可通过 useLoadingBar() 取得同一实例

关于 LoadingBarProvider 与 LoadingBar

  • LoadingBarProvider 内部渲染一个 LoadingBar 组件,并通过 provide/inject 向下提供 useLoadingBar() 所需的 API,自身不渲染任何可见内容
  • 加载条的配置属性(loadingBarSize / colorLoading / colorFinish / colorError / loadingBarStyle / to 等)会透传给内部的 LoadingBar,因此直接参考下方 LoadingBar Props 设置即可
  • 使用 useLoadingBar() 时,组件级配置设置在 <LoadingBarProvider> 上(无法直接接触内部 LoadingBar);逐次调用的参数差异通过 start(from, to, status) 传入

1. 在应用根节点放置 LoadingBarProvider

App.vue

vue
<script setup lang="ts">
import { LoadingBarProvider } from 'vue-amazing-ui'
</script>
<template>
  <LoadingBarProvider>
    <RouterView />
  </LoadingBarProvider>
</template>

2. 在任意层级组件中调用 useLoadingBar()

XXX.vue

vue
<script setup lang="ts">
import { useLoadingBar } from 'vue-amazing-ui'
const loadingBar = useLoadingBar()
function onClick() {
  loadingBar.start()
}
</script>
<template>
  <Button @click="onClick">开始加载</Button>
</template>

本文档网站已在主题层全局包裹 <LoadingBarProvider>,以下演示均通过 useLoadingBar() 获取实例(与真实项目用法一致);需要不同配置的演示,均通过页面内局部嵌套 <LoadingBarProvider> 实现。

基本使用 ​

点击「开始」后加载条出现在页面顶部


开始
结束
报个错
Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
import { useLoadingBar } from 'vue-amazing-ui'
const loadingBar = useLoadingBar()
const finishDisabled = ref(true)
function onStart() {
  loadingBar.start()
  finishDisabled.value = false
}
function onFinish() {
  loadingBar.finish()
  finishDisabled.value = true
}
function onError() {
  finishDisabled.value = true
  loadingBar.error()
}
</script>
<template>
  <Space>
    <Button type="primary" @click="onStart">开始</Button>
    <Button :disabled="finishDisabled" @click="onFinish">结束</Button>
    <Button type="danger" @click="onError">报个错</Button>
  </Space>
</template>

局部加载条 ​

通过 to 指定加载条的挂载位置,配合 container-style 让它落在局部容器内;容器内的按钮通过 <LoadingBarProvider> 的 @ready 事件取到该作用域内的 api


开始
结束
报个错
Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
import { LoadingBarProvider } from 'vue-amazing-ui'
import type { LoadingBarApi } from 'vue-amazing-ui'
const localCardRef = ref<HTMLDivElement>()
const localLoadingBar = ref<LoadingBarApi>()
const localFinishDisabled = ref(true)
function onLocalStart() {
  localLoadingBar.value?.start()
  localFinishDisabled.value = false
}
function onLocalFinish() {
  localLoadingBar.value?.finish()
  localFinishDisabled.value = true
}
function onLocalError() {
  localFinishDisabled.value = true
  localLoadingBar.value?.error()
}
</script>
<template>
  <div class="card-container">
    <div ref="localCardRef" class="card-target"></div>
    <LoadingBarProvider
      :to="localCardRef"
      :container-style="{ position: 'absolute' }"
      @ready="localLoadingBar = $event"
    >
      <Space>
        <Button type="primary" @click="onLocalStart">开始</Button>
        <Button :disabled="localFinishDisabled" @click="onLocalFinish">结束</Button>
        <Button type="danger" @click="onLocalError">报个错</Button>
      </Space>
    </LoadingBarProvider>
  </div>
</template>
<style lang="less" scoped>
.card-container {
  position: relative;
  display: flex;
  align-items: center;
  max-width: 720px;
  height: 120px;
  padding: 16px 24px;
  border: 1px solid #d9d9d9;
  overflow: hidden;
}
.card-target {
  position: absolute;
  inset: 0;
  pointer-events: none;
}
</style>

自定义加载条样式 ​

通过 loading-bar-size / color-loading / color-finish / color-error 自定义加载条的高度与各状态颜色


开始
结束
报个错
Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
import { LoadingBarProvider } from 'vue-amazing-ui'
import type { LoadingBarApi } from 'vue-amazing-ui'
const customCardRef = ref<HTMLDivElement>()
const customLoadingBar = ref<LoadingBarApi>()
const customFinishDisabled = ref(true)
function onCustomStart() {
  customLoadingBar.value?.start()
  customFinishDisabled.value = false
}
function onCustomFinish() {
  customLoadingBar.value?.finish()
  customFinishDisabled.value = true
}
function onCustomError() {
  customFinishDisabled.value = true
  customLoadingBar.value?.error()
}
</script>
<template>
  <div class="card-container">
    <div ref="customCardRef" class="card-target"></div>
    <LoadingBarProvider
      :to="customCardRef"
      :container-style="{ position: 'absolute' }"
      :loading-bar-size="5"
      color-loading="#2db7f5"
      color-finish="#52c41a"
      color-error="magenta"
      @ready="customLoadingBar = $event"
    >
      <Space>
        <Button type="primary" @click="onCustomStart">开始</Button>
        <Button :disabled="customFinishDisabled" @click="onCustomFinish">结束</Button>
        <Button type="danger" @click="onCustomError">报个错</Button>
      </Space>
    </LoadingBarProvider>
  </div>
</template>

按状态自定义样式 ​

loading-bar-style 按状态(loading / finish / error)给进度条注入任意样式,可实现渐变、阴影等 color-loading / color-finish / color-error 无法表达的定制;与颜色属性设置同名样式时,以内联样式为准


开始
结束
报个错
Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
import { LoadingBarProvider } from 'vue-amazing-ui'
import type { LoadingBarApi } from 'vue-amazing-ui'
const stateCardRef = ref<HTMLDivElement>()
const stateLoadingBar = ref<LoadingBarApi>()
const stateFinishDisabled = ref(true)
const stateLoadingBarStyle = {
  loading: {
    background: 'linear-gradient(90deg, #2db7f5, #52c41a)',
    boxShadow: '0 0 8px #2db7f5'
  },
  finish: {
    background: 'linear-gradient(90deg, #52c41a, #2db7f5)',
    boxShadow: '0 0 8px #52c41a'
  },
  error: {
    background: 'linear-gradient(90deg, #ff4d4f, #faad14)'
  }
}
function onStateStart() {
  stateLoadingBar.value?.start()
  stateFinishDisabled.value = false
}
function onStateFinish() {
  stateLoadingBar.value?.finish()
  stateFinishDisabled.value = true
}
function onStateError() {
  stateFinishDisabled.value = true
  stateLoadingBar.value?.error()
}
</script>
<template>
  <div class="card-container">
    <div ref="stateCardRef" class="card-target"></div>
    <LoadingBarProvider
      :to="stateCardRef"
      :container-style="{ position: 'absolute' }"
      :loading-bar-style="stateLoadingBarStyle"
      @ready="stateLoadingBar = $event"
    >
      <Space>
        <Button type="primary" @click="onStateStart">开始</Button>
        <Button :disabled="stateFinishDisabled" @click="onStateFinish">结束</Button>
        <Button type="danger" @click="onStateError">报个错</Button>
      </Space>
    </LoadingBarProvider>
  </div>
</template>

主题跟随 ​

加载条默认取 ConfigProvider 中 LoadingBar.primaryColor 生成的调色板,改变主色即可让加载中 / 加载完成颜色同步跟随


primaryColor:
#18a058
开始
结束
报个错
Show Code
vue
<script setup lang="ts">
import { computed, ref } from 'vue'
import { LoadingBarProvider } from 'vue-amazing-ui'
import type { ConfigProviderTheme, LoadingBarApi } from 'vue-amazing-ui'
const themeCardRef = ref<HTMLDivElement>()
const themeLoadingBar = ref<LoadingBarApi>()
const themeFinishDisabled = ref(true)
const themeColor = ref('#18a058')
const loadingBarTheme = computed<ConfigProviderTheme>(() => ({
  LoadingBar: {
    primaryColor: themeColor.value
  }
}))
function onThemeStart() {
  themeLoadingBar.value?.start()
  themeFinishDisabled.value = false
}
function onThemeFinish() {
  themeLoadingBar.value?.finish()
  themeFinishDisabled.value = true
}
function onThemeError() {
  themeFinishDisabled.value = true
  themeLoadingBar.value?.error()
}
</script>
<template>
  <Flex vertical>
    <Space align="center" class="mb10">
      primaryColor:
      <ColorPicker :width="200" v-model:value="themeColor" />
    </Space>
    <ConfigProvider :theme="loadingBarTheme">
      <div class="card-container">
        <div ref="themeCardRef" class="card-target"></div>
        <LoadingBarProvider
          :to="themeCardRef"
          :container-style="{ position: 'absolute' }"
          @ready="themeLoadingBar = $event"
        >
          <Space>
            <Button type="primary" @click="onThemeStart">开始</Button>
            <Button :disabled="themeFinishDisabled" @click="onThemeFinish">结束</Button>
            <Button type="danger" @click="onThemeError">报个错</Button>
          </Space>
        </LoadingBarProvider>
      </div>
    </ConfigProvider>
  </Flex>
</template>

APIs ​

LoadingBar ​


组件级配置属性(class / style 亦会透传到加载条容器):使用 useLoadingBar() 时设置在 <LoadingBarProvider> 上(会透传给内部 LoadingBar),直接使用 <LoadingBar> 组件时设置在 <LoadingBar> 上,两者等价

参数说明类型默认值
containerClass加载条容器的类名stringundefined
containerStyle加载条容器的样式CSSProperties{}
loadingBarSize加载条大小,单位 pxnumber2
colorLoading加载中颜色stringundefined
colorFinish加载完成颜色stringundefined
colorError加载错误颜色string'#ff4d4f'
loadingBarStyle按状态自定义加载条样式,可选 loading / finish / error,取值为样式字符串或 CSSProperties{ loading?: string | CSSProperties, finish?: string | CSSProperties, error?: string | CSSProperties }undefined
to加载条的挂载位置,可选:元素标签名(例如 'body')或者元素本身,false 会待在原地string | HTMLElement | false'body'

组件上的 class / style 透传到加载条容器 .loading-bar-wrap(等价于 containerClass / containerStyle)。

colorLoading / colorFinish 默认取 LoadingBar.primaryColor 生成的调色板(跟随主题),colorError 默认 #ff4d4f。

loadingBarStyle 以内联样式作用于内层进度条:与 loadingBarSize / colorLoading / colorFinish / colorError 设置同一属性冲突时,以其为准;未提供 finish 时,完成态回落到 loading 的样式;error 态仅取 error,未提供时不注入任何自定义样式。

Methods ​

useLoadingBar() 返回的 LoadingBarApi,或通过 <LoadingBar> / <LoadingBarProvider> 的 @ready 事件获取:

名称说明类型
start开始加载,from / to 为进度百分比(默认 0 → 80),status 决定起始状态的类名(from?: number, to?: number, status?: 'starting' | 'error') => Promise<void>
finish结束加载,进度补满到 100% 后隐藏() => Promise<void>
error出现错误,进度条切为错误色并隐藏() => void

Events ​

名称说明类型
ready实例挂载完成时触发,参数为该实例的 api(api: LoadingBarApi) => void

在 setup 外使用 ​

createDiscreteApi()(脱离组件树) ​


适用于 axios 拦截器、路由守卫、Pinia action 等任意位置:内部会创建一个独立的应用实例,因此可在任意位置调用,无需外层 LoadingBarProvider

注意

  • 主题使用内置默认值;如需自定义,通过第二个参数 configProviderProps(支持 Ref / computed 响应式)显式传入,详见 全局化配置 ConfigProvider「主题同步到离散 API」
  • 每次调用都会创建一套独立实例(独立的容器与加载条),建议缓存返回值复用,避免重复创建;不再使用时可通过返回的 dispose() 销毁该实例
  • 内部会访问 document,SSR 场景请在客户端(点击回调、onMounted 等)中调用
  • 不建议与 useLoadingBar() 在同一 App 中混用:两者各自持有独立实例,加载条互不影响

XXX.ts(任意 .ts 文件)

ts
import { createDiscreteApi } from 'vue-amazing-ui'

// 任意位置调用,无需外层 LoadingBarProvider
const { loadingBar } = createDiscreteApi(['loadingBar'])

// 例:路由守卫
router.beforeEach(() => {
  loadingBar.start()
})
router.afterEach(() => {
  loadingBar.finish()
})
开始
结束
报个错
Show Code
vue
<script setup lang="ts">
import { ref } from 'vue'
import { createDiscreteApi } from 'vue-amazing-ui'
import type { DiscreteApiInstance, LoadingBarApi } from 'vue-amazing-ui'
// 惰性单例:仅首次调用时创建,避免重复创建独立实例与挂载 DOM
let discreteLoadingBar: DiscreteApiInstance<'loadingBar'> | null = null
const discreteFinishDisabled = ref(true)
function getDiscreteLoadingBar(): LoadingBarApi {
  if (!discreteLoadingBar) {
    discreteLoadingBar = createDiscreteApi(['loadingBar'])
  }
  return discreteLoadingBar.loadingBar
}
function onDiscreteStart() {
  getDiscreteLoadingBar().start()
  discreteFinishDisabled.value = false
}
function onDiscreteFinish() {
  getDiscreteLoadingBar().finish()
  discreteFinishDisabled.value = true
}
function onDiscreteError() {
  discreteFinishDisabled.value = true
  getDiscreteLoadingBar().error()
}
</script>
<template>
  <Space>
    <Button type="primary" @click="onDiscreteStart">开始</Button>
    <Button :disabled="discreteFinishDisabled" @click="onDiscreteFinish">结束</Button>
    <Button type="danger" @click="onDiscreteError">报个错</Button>
  </Space>
</template>

Released under the MIT License.