Angular 加载指示器与遮罩层 | ng-hub-ui-loading

Angular 加载组件,提供 spinner、dots、bars、pulse、ring 五种指示器,支持 inline、overlay 与 fullscreen 三种模式,并附带用于全应用阻塞遮罩的服务。

最后更新 2026年9月5日

概览

团队为何搜索这个库

当某个区块、某个容器或整个应用需要表明正在处理,又不希望每个视图各自手写一套指示器和遮罩时,请使用 ng-hub-ui-loading。

安装

npm install ng-hub-ui-loading

跳转到

适用于

  • 路由与数据加载
  • 表单提交遮罩
  • 全应用阻塞式操作
  • 带品牌标识的启动画面
  • 导航栏下的页面进度条

关于 loading

ng-hub-ui-loading 是一个独立的 Angular 组件,以三种模式呈现不确定的加载状态:`inline` 作为文档流中的区块,`overlay` 绝对定位覆盖其父容器,`fullscreen` 固定于视口。它内置五种纯 CSS 指示器——spinner、dots、bars、pulse 与 ring——并提供三档尺寸、可选的提示文案,以及可选的品牌图片,图片支持 `none`、`spin`、`pulse` 三种动效。`HubLoadingService` 以编程方式驱动全局全屏遮罩,并对并发调用方进行引用计数,因此并行的请求不会互相撤掉遮罩。颜色、尺寸与时长都是 `--hub-loading-*` 自定义属性,另有 `hub-loading-theme()` Sass mixin 用于整体重塑样式;组件默认具备无障碍能力,带有 `role=status`、`aria-live=polite` 与 `aria-busy`,并遵循 `prefers-reduced-motion`。 与之并列,`hub-loading-bar` 用来告诉读者页面本身正在路上——导航栏下的那条细带,可以画在文档流中,挂在已定位的导航栏上,或按 `--hub-loading-bar-offset` 固定到 viewport。`HubLoadingBarService` 同样对调用方计数,留出一段宽限期,让很快完成的工作不会让进度条闪一下,并朝着自己永远到不了的终点推进:只有 `complete()` 可以显示 100%。`provideHubLoadingBarRouter()` 与 `hubLoadingBarInterceptor` 把它接到路由和 HTTP 上,而两者互不相识。

功能指南

内联块

`inline` 之所以是默认模式,是因为一块尚且为空的区域本就该先把内容将要占据的空间留出来:该块参与正常的文档流,因此真实内容到达时不会发生跳动。`message` 渲染在指示器下方,标签之间投影的任何内容再渲染在消息下方——那是放置取消操作,或提示“本次操作比平时更久”的位置。宿主元素带有 `role="status"`、`aria-live="polite"` 与 `aria-busy="true"`,因此屏幕阅读器会在消息出现时读到它,而不会打断正在朗读的内容。

示例:
内联块基础

内联块的三种实用形态:仅指示器、指示器加消息,以及消息下方投影一个取消操作。

Indicator only

Loading your workspace

With a message

Importing 1,248 rows

With projected content

The block is announced as role="status" with aria-live="polite", so a screen reader reads the message when it appears without interrupting whatever is being read.

代码
导入:
模板:
组件:

指示器与强调色

库内置五种纯 CSS 指示器——`spinner`、`dots`、`bars`、`pulse` 与 `ring`——因此不会引入任何图片资源或图标字体。三档尺寸预设了 `--hub-loading-size`,而当布局需要这三档之外的尺寸时,该令牌本身仍可单独覆盖。`color` 并非普通的 CSS 颜色:它会经过 `resolveHubAccent()`,把 `primary` 这样的裸名称解析为跟随主题的设计系统令牌,而 hex、`oklch()` 字面量或 `var(...)` 引用则原样使用。

示例:
变体、尺寸与强调色

内置的五种指示器、三档尺寸,以及强调色可以采取的三种写法——语义名称、CSS 颜色字面量与 `var(...)` 引用。

Variants
spinner
dots
bars
pulse
ring
Sizes
size="sm"
size="md"
size="lg"

Each step is a preset for the --hub-loading-size token. Override that token directly when a layout needs a size the three steps do not cover.

Accents
color="primary"
color="success"
color="danger"
color="#7c3aed"
color="var(--hub-sys-color-warning)"

A bare name resolves to var(--hub-sys-color-<name>) and tracks the active theme. A hex, an oklch() or a var(...) is used verbatim.

代码
导入:
模板:
组件:

Overlay 与全屏

`overlay` 覆盖的是某一块区域,而不是整个页面。它采用绝对定位,因此由最近的已定位祖先决定被覆盖的范围——请给该容器加上 `position: relative`,否则 overlay 会一路向上逃逸到碰巧被定位的那个祖先。这样限定范围可以让页面其余部分仍能滚动与操作。`fullscreen` 固定于 viewport,正是 `HubLoadingService` 挂载到 `document.body` 上的那一层;它位于所有组件子树之外,因此不会被祖先的 `overflow` 或层叠上下文裁切。除非关闭 `backdrop`,两种模式都会绘制半透明遮罩。

示例:
容器 overlay

借助卡片自身的 `position: relative` 把 overlay 限制在这张卡片内,页面其余部分仍可滚动。切换 `backdrop`,即可看出后台刷新与「使屏幕内容失效的操作」之间的差别。

Order #4821

3 items · delivered 14 Aug 2026

Subtotal
212.00 €
Shipping
9.90 €
VAT (21%)
26.70 €
Total
248.60 €

Turn the backdrop off to keep the content readable underneath — useful when the work is a background refresh rather than something that invalidates what is on screen.

代码
导入:
模板:
组件:
全屏服务

从 TypeScript 驱动的 `HubLoadingService`。两个相互重叠的请求说明了引用计数为何重要:第一次 `hide()` 不会撤下 overlay,因为第二个调用方仍持有引用,而 `update()` 会在进行途中改写消息。

The overlay covers the whole viewport, so this demo dismisses it for you: every request releases its own reference, and a watchdog forces a hideAll() after 5 seconds no matter what.
References held
0
isLoading()
false
Calls

Nothing yet.

代码
导入:
模板:
组件:

品牌化与主题化

`image` 会用你自己的标识替换内置指示器,并以 `none`、`spin` 或 `pulse` 赋予动效:`spin` 只在径向对称的标识上才好看,而 `pulse` 能让文字标识保持端正易读。所有视觉相关的设定都在 `--hub-loading-*` 令牌里,声明于 `:where(.hub-loading)`,因此任何祖先都能设置它们——强调色、尺寸、速度、线条粗细、间距、图像尺寸、文本颜色,以及遮罩的色调与模糊。Sass 混入 `hub-loading-theme()` 一次调用即可设定整套令牌,而 `provideHubLoading()` 无需改动任何模板就能为整个应用重设默认值。

示例:
品牌图像

以品牌标识替换内置指示器,并分别配以三种图像动效,让 `spin`、`pulse` 与 `none` 之间的取舍一目了然。

Preparing your report

imageAnimation="none"

Preparing your report

imageAnimation="spin"

Preparing your report

imageAnimation="pulse"

Any URL works — an asset path, an imported file or, as here, an inline data URI. Size the mark with --hub-loading-image-size rather than size, which drives the built-in indicators.

代码
导入:
模板:
组件:
CSS 变量主题化

通过设置在包裹元素上的 `--hub-loading-*` 令牌进行实时主题化,包括仅在 `overlay` 与 `fullscreen` 模式下才起作用的遮罩色调与模糊。

Inline — accent, size, speed, thickness

Overlay preview

The backdrop tint and blur only apply in overlay and fullscreen modes. The tint is mixed from --hub-sys-surface-page, so it veils this text with the theme's own surface instead of a fixed colour — drop it to zero and the card stays fully legible underneath.

Refreshing

The same overrides written once, in Sass, are in the CSS tab — that is what hub-loading-theme() is for.

代码
导入:
模板:
组件:

页面进度条

`hub-loading-bar` 是那条细带,用来告诉读者页面本身正在路上——就是导航栏下面的那一条。三个决定让它可信。它对调用方计数:一次导航加上页面发出的三个请求就是四个引用,进度条随最后一个结束,而不是第一个。它在画出任何东西之前先等待:在宽限期内完成的工作根本不会出现进度条,因为一条 40 毫秒的路由闪一下进度条,读起来像故障而不像快。它的自动推进随着填充而减速,并且停在终点之前——这里没有人知道真实的百分比,所以只有 `complete()` 可以显示 100%,因为只有 `complete()` 知道那是真的。用 `mode="overlay"` 放进一个已定位的导航栏,或者当导航栏本身固定时,用 `mode="fixed"` 配合 `--hub-loading-bar-offset`。

示例:
页面进度条

挂在模拟导航栏上的进度条。三条路由展示三种行为:普通的会推进,慢的能看出推进在减速,40 毫秒的那条则根本不画进度条。

Acme
Orders

This page arrived without you watching a spinner.

progress 0% · painted: false
代码
导入:
模板:
组件:
已知与未知的进度

绑定 `progress` 会把进度条交给调用方并公开 `aria-valuenow`;`indeterminate` 改为扫动并隐去数值。第三种状态 `null` 则把它收起来。

Known percentage
[progress]="null"

A real value, so the bar announces it. Reaching 100% is the caller's call, not the trickle's.

No percentage at all
indeterminate

A sweep instead of a fill, for a stream or a job that reports no stages. No value is announced, because there is none.

Both bars are mode="inline", so each reserves its own row and nothing on the card moves when a bar appears or goes away.

代码
导入:
模板:
组件:
路由与 HTTP 接入

进度条为什么要对调用方计数:一次导航加三个请求就是四个引用,进度条随最后一个结束。代码展示了 `provideHubLoadingBarRouter()`、拦截器与排除方式。

Dashboard
Callers
0
isActive()
false
progress()
0%
Calls

Nothing yet.

代码
导入:
模板:
组件:

核心特性

最近更改

Version 22.1.0 - 9/5/26, 12:00 AM

added: hub-loading-bar: the thin page-progress strip that sits under the navbar, in three placements — inline in the flow, overlay against a positioned ancestor, or fixed to the viewport at --hub-loading-bar-offset.

added: HubLoadingBarService, with reference-counted start() / complete(), an anti-flicker grace period so fast work never paints a bar at all — set delay to 0 to opt out and reveal synchronously — and a trickle that decelerates as it fills and stops short of the end, since only complete() may show 100%.

added: provideHubLoadingBarRouter(), which runs the bar for the length of a navigation, including one a guard rejects, and hubLoadingBarInterceptor with withoutHubLoadingBar() to keep polls and heartbeats out of the count.

added: Determinate mode through the progress input, which publishes aria-valuenow, and an indeterminate sweep. Both withhold the value while the number is invented, which is how ARIA marks a progressbar of unknown position.

added: provideHubLoadingBar(), the HUB_LOADING_BAR_CONFIG token, the exported hubLoadingBarTrickle() curve, thirteen --hub-loading-bar-* tokens and the hub-loading-bar-theme() Sass mixin.

Version 22.0.0 - 8/24/26, 12:00 AM

added: Initial release of hub-loading: one component covering the inline block, the container overlay and the fullscreen layer, with role="status", aria-live="polite" and aria-busy set on the host.

added: Five pure-CSS indicators — spinner, dots, bars, pulse and ring — in three size steps, with no image or font dependency.

added: Accent resolution through resolveHubAccent() from ng-hub-ui-utils: a bare name becomes a --hub-sys-color-* token and follows the theme, while a hex, an oklch() or a var(...) is used verbatim.

added: Optional image input with none, spin and pulse animations, replacing the built-in indicator with a brand mark.

added: HubLoadingService for the fullscreen overlay, with a reference counter so concurrent callers cannot unblock the screen out from under each other, plus update() to re-dress the live overlay and hideAll() to force the count to zero. SSR-safe: a no-op without a DOM.

added: provideHubLoading() and the HUB_LOADING_CONFIG token, supplying application-wide defaults to both the component and the service.

added: Theming through the --hub-loading-* token ladder and the hub-loading-theme() Sass mixin, shipped at ng-hub-ui-loading/styles.