Sunshine终极指南:打造免费高性能游戏串流服务器的完整方案
【免费下载链接】ngx-bootstrap
Fast and reliable Bootstrap widgets in Angular (supports Ivy engine)
导读
在 ngx-bootstrap 中,progressbar 组件允许通过属性绑定逐条设置 max、animate、striped 与 type,但当项目需要统一风格的进度条时,逐条配置既繁琐又容易遗漏。本文围绕官方文档 progressbar.examples.config-default.use-case.md 描述的 "Configuring defaults" 示例,讲解如何通过依赖注入覆盖 ProgressbarConfig,实现全局默认值配置,并深入源码剖析其工作原理、适用场景与注意事项,帮助你在项目中一次性定制所有进度条的默认外观与行为。
一、场景概述:Configuring defaults 示例要解决什么问题
1.1 用例文档描述的目标
官方 spec 文档 progressbar.examples.config-default.use-case.md 定义了这个演示用例(适用于 BS version 3&4 的 DEMO 页面):
- Primary Actor(主要参与者):User
- Scope(作用范围):Ngx-bootstrap DEMO,Bootstrap 版本 3 与 4
- Goal(目标):向用户展示如何配置 progressbar 的默认值
其主成功场景(Main success scenario)为:
- 用户打开 Progressbar 演示页面;
- 用户点击 Configuring defaults 子菜单(变体场景:用户滚动到该子菜单);
- 用户看到 1 个具有特定 value 和 type 的进度条(具体样式见 Template 源码);
- 组件源码应通过
ProgressbarConfig编写。
也就是说,这个示例的核心教学点不是某个进度条的属性绑定,而是 "如何通过 ProgressbarConfig 服务为整个 progressbar 组件提供一套全局默认配置"。
1.2 与其它 progressbar 示例的定位差异
在文档目录 docs/spec/progressbar 下,与该用例并列的还有 static、dynamic、stacked 三个用例:
- Static:静态绑定
value、type等属性; - Dynamic:通过组件逻辑动态改变
value与type; - Stacked:使用
BarValue[]数组实现多段堆叠进度条; - Configuring defaults:不逐条传属性,而是通过注入覆盖全局默认配置。
四者互补:前三者演示"单次使用"层面的配置,而本用例演示"全局约定"层面的配置,适用于项目中需要统一进度条风格的场景。
二、核心配置类:ProgressbarConfig 源码解析
配置默认值的落点是一个可注入的服务类 ProgressbarConfig,源码位于 src/progressbar/progressbar.config.ts:
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class ProgressbarConfig {
/** if `true` changing value of progress bar will be animated */
animate = false;
/** If `true`, striped classes are applied */
striped = false;
/** maximum total value of progress element */
max = 100;
}
该类由三个可配置属性组成,含义与默认值如下:
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
animate | boolean | false | 为 true 时进度条值变化带动画(对应 .progress-bar-animated) |
striped | boolean | false | 为 true 时应用条纹样式类(对应 .progress-bar-striped) |
max | number | 100 | 进度条的总量上限,用于计算百分比宽度 |
它被声明为 providedIn: 'root' 的 root 级服务,因此默认情况下在整个应用共享同一个实例;在组件/模块层面通过 providers 覆盖时,则会生成局部实例(详见下文第三节)。注意:type(success/info/warning/danger)不在全局默认配置范围内,它属于每个进度条实例的语义属性,需按组件单独指定或交给 BarComponent 的内置默认值 'info'(见 src/progressbar/bar.component.ts)。
三、全局默认值如何生效:依赖注入链路剖析
3.1 配置值进入组件的入口
ProgressbarConfig 的默认值通过组件输入属性的初始值进入组件。查看 src/progressbar/progressbar.component.ts:
export class ProgressbarComponent {
/** maximum total value of progress element */
max = input<number>(this._config.max);
/** if `true` changing value of progress bar will be animated */
animate = input<boolean>(this._config.animate);
/** If `true`, striped classes are applied */
striped = input<boolean>(this._config.striped);
/** provide one of the four supported contextual classes: `success`, `info`, `warning`, `danger` */
type = input<ProgressbarType | undefined>();
/** current value of progress bar. Could be a number or array of objects
* like {"value":15,"type":"info","label":"15 %"}
*/
value = input<number | BarValue[]>(0);
isStacked = computed(() => Array.isArray(this.value()));
...
constructor(private _config: ProgressbarConfig) {
}
}
关键点在于:
max、animate、striped三个输入使用this._config.xxx作为默认值(Angular 17+ 的input()信号式 API);- 组件构造时注入
ProgressbarConfig(constructor(private _config: ProgressbarConfig)); - 因此,只要在合适的注入器层级覆盖了
ProgressbarConfig,未显式绑定的max/animate/striped就会自动取到覆盖后的值; - 而显式绑定(如
[max]="200")的优先级始终高于全局默认值,属于"默认值兜底、显式绑定优先"的机制。
3.2 演示组件中的覆盖方式
官方 DEMO 的组件实现位于 libs/doc-pages/progressbar/src/lib/demos/config/config.ts:
import { Component } from '@angular/core';
import { ProgressbarConfig } from 'ngx-bootstrap/progressbar';
// such override allows to keep some initial values
export function getProgressbarConfig(): ProgressbarConfig {
return Object.assign(new ProgressbarConfig(), { animate: true, striped: true, max: 150 });
}
@Component({
// eslint-disable-next-line @angular-eslint/component-selector
selector: 'demo-progressbar-config',
templateUrl: './config.html',
providers: [{ provide: ProgressbarConfig, useFactory: getProgressbarConfig }],
standalone: false
})
export class DemoProgressbarConfigComponent {}
对应的模板 libs/doc-pages/progressbar/src/lib/demos/config/config.html:
<div class="mb-2">
<progressbar class="progress-striped active" [value]="136" type="danger"><i>136 / 150</i></progressbar>
</div>
这份代码体现了三层含义:
- 保留初始值的覆盖模式:工厂函数
getProgressbarConfig()先new ProgressbarConfig()(得到默认值animate: false, striped: false, max: 100),再用Object.assign覆盖为{ animate: true, striped: true, max: 150 }。注释 "such override allows to keep some initial values" 明确说明:这种写法能保留类中的初始值,避免逐项手写全部字段——即便将来ProgressbarConfig新增字段,默认值也不会丢失。 - 局部注入覆盖:
providers: [{ provide: ProgressbarConfig, useFactory: getProgressbarConfig }]在组件注入器层级提供了新的ProgressbarConfig实例。根据 Angular 依赖注入的层级解析规则,该组件树内的progressbar会优先解析到这个局部实例,从而不影响应用其它区域的进度条。 - 模板只传个别属性:模板中仅显式绑定了
[value]="136"和type="danger",未绑定max/animate/striped——它们全部取自覆盖后的全局默认值(max=150、动画、条纹),最终渲染出"136 / 150"、danger 红色、带动画和条纹的进度条,与 spec 文档"看到 1 个具有特定 value 和 type 的进度条"的验收条件一致。
3.3 从 spec 到实现的对应关系
对照用例文档与 DEMO 源码,可得到如下映射:
| spec 文档中的步骤 | 对应实现 |
|---|---|
| 用户点击 Configuring defaults 子菜单 | 在 libs/doc-pages/progressbar/src/lib/progressbar-section.list.ts 中注册为 title: 'Configuring defaults', anchor: 'bs3-config' 的 demo 条目 |
| 组件源码通过 ProgressbarConfig 编写 | config.ts 中的 providers 与 useFactory |
| 展示 1 个特定 value 和 type 的进度条 | config.html 中 [value]="136"、type="danger" 及文字标签 <i>136 / 150</i> |
四、渲染与计算原理:默认值如何变成可见样式
4.1 外层 progressbar 到内层 bar 的传递
progressbar 组件本身不直接渲染视觉元素,它通过模板把配置转发给内部的 bar 子组件。见 src/progressbar/progressbar.component.html:
@if (!isStacked()) {
<bar [type]="type()" [value]="_value()" [max]="max()" [animate]="animate()" [striped]="striped()">
<ng-content></ng-content>
</bar>
} @else {
@for (item of _values(); track item) {
<bar
[type]="item.type" [value]="item.value" [max]="item.max || max()" [animate]="animate()" [striped]="striped()">{{ item.label }}</bar>
}
}
单值模式下,max()、animate()、striped() 直接来自组件输入(其默认值即 ProgressbarConfig);value 为数组时进入堆叠模式(Stacked),每个 bar 还可通过 item.max 覆盖最大上限。
4.2 bar 的百分比计算与类型样式
真正负责"算宽度、加样式"的是 BarComponent,见 src/progressbar/bar.component.ts:
export class BarComponent {
/** maximum total value of progress element */
max = input<number>(100);
/** current value of progress bar */
value = input<number | undefined>(0);
/** if `true` changing value of progress bar will be animated */
animate = input<boolean | undefined>(false);
/** If `true`, striped classes are applied */
striped = input<boolean | undefined>(false);
/** provide one of the four supported contextual classes: `success`, `info`, `warning`, `danger` */
type = input<ProgressbarType | undefined>('info');
percent = 100;
...
constructor(
private el: ElementRef,
private renderer: Renderer2
) {
// Watch for value and max changes to update percent
effect(() => {
const currentValue = this.value() ?? 0;
const currentMax = this.max() || 100;
this.percent = 100 * (Number(currentValue) / Number(currentMax));
});
// Watch for type changes to update classes
effect(() => {
const currentType = this.type();
this.applyTypeClasses(currentType);
});
}
}
核心逻辑:
- 百分比公式:
percent = 100 * value / max。以示例value=136, max=150计算,约为90.67%,进度条宽度按此百分比填充; - 宿主绑定:
'[style.width.%]': 'percent'将百分比映射为宽度,'[class.progress-bar-animated]': 'animate()'、'[class.progress-bar-striped]': 'striped()'控制动画与条纹类(见 bar.component.ts); - 类型样式:
applyTypeClasses()依据ProgressbarType(定义于 src/progressbar/progressbar-type.interface.ts)动态增删progress-bar-{type}与bg-{type}类,切换类型时会先移除旧类型类再添加新类型类。
4.3 测试对默认值行为的验证
仓库单元测试 src/progressbar/testing/progressbar.component.spec.ts 印证了上述行为:
- 默认值测试:
<progressbar></progressbar>渲染后,外层元素包含progress类且max属性为'100'(对应ProgressbarConfig.max = 100); - 百分比测试:
[max]="100" [value]="60"时bar的style.width为'60%'; - 动态切换测试:将
max从 100 改为 200、value从 75 改为 100 后,宽度从'75%'变为'50%',类型类从progress-bar-warning变为progress-bar-danger; - 类型绑定测试:切换
type时progress-bar-striped等其它类名不会被覆盖,且bg-{type}类同步增删。
这些用例说明:无论默认值来自何处(ProgressbarConfig 或属性绑定),最终都收敛到同一套"百分比计算 + 类型类管理"逻辑,行为一致、可预测。
五、实战:在真实项目中配置 progressbar 全局默认值
5.1 安装与引入
通过 Angular CLI 示意图安装并引入 progressbar 模块(官方 DEMO 的安装提示见 progressbar-section.list.ts 中的 importInfo 字段):
ng add ngx-bootstrap --component progressbar
或在代码中手动引入。组件已支持 standalone,见 src/progressbar/progressbar.component.ts;也提供模块方式聚合导出,见 src/progressbar/progressbar.module.ts:
// 模块方式
import { NgModule } from '@angular/core';
import { ProgressbarModule } from 'ngx-bootstrap/progressbar';
@NgModule({
imports: [ProgressbarModule],
})
export class AppModule {}
5.2 为整个应用定制默认值
如果想全局生效(所有进度条默认 max=150、带动画、带条纹),在根模块或根组件的 providers 中覆盖:
import { ProgressbarConfig } from 'ngx-bootstrap/progressbar';
export function getProgressbarConfig(): ProgressbarConfig {
return Object.assign(new ProgressbarConfig(), {
animate: true,
striped: true,
max: 150
});
}
// 在 AppModule 的 providers 中:
providers: [
{ provide: ProgressbarConfig, useFactory: getProgressbarConfig }
]
5.3 为局部模块/组件定制默认值
若只需某个功能模块内的进度条统一风格,把同样的 provider 放进该模块或组件的 providers 即可;Angular 注入器按层级就近解析,外层应用配置不受影响。这也是官方 DEMO 组件 config.ts 的做法。
5.4 使用建议与优先级规则
- 优先级:显式属性绑定 > 局部
ProgressbarConfig> 全局ProgressbarConfig> 类内建默认值。即"默认值兜底、显式绑定优先"; - 保留初始值:推荐
Object.assign(new ProgressbarConfig(), {...})的覆盖写法,而不是直接手写一个对象字面量——后者会丢失ProgressbarConfig未来的新增字段,导致隐性行为差异; - type 不参与全局默认:
type属于实例语义,需要时在模板上绑定(如type="danger"),或依赖BarComponent的默认值'info'; - 值超过 max 的表现:示例中
value=136 < max=150,处于正常范围;若value超过max,按百分比公式计算出的宽度将超过 100%,渲染效果取决于外层容器,因此合理设置max是全局配置的关键。
六、小结
"Configuring defaults" 示例展示了 ngx-bootstrap progressbar 一种优雅的全局配置机制:通过覆盖可注入的 ProgressbarConfig(animate、striped、max 三个默认值),配合 Angular 依赖注入的层级解析,即可在不改动任何模板绑定的前提下统一项目进度条风格;useFactory + Object.assign 的写法既保留了初始值,又避免逐项手写。从源码链路看,配置值经 ProgressbarComponent 的输入默认值进入组件,转发给 BarComponent 完成百分比计算与样式类管理,整个过程有 单元测试 覆盖,行为可预期、可验证。想要继续深入,可对比阅读同一目录下的 static 示例、dynamic 示例 与 stacked 示例,以完整掌握 progressbar 的三种配置维度。
【免费下载链接】ngx-bootstrap
Fast and reliable Bootstrap widgets in Angular (supports Ivy engine)
更多推荐


所有评论(0)