Angular
所有组件都是 standalone 的,使用 signal inputs / models,并支持 zoneless 变更检测。
配置
ts
import { bootstrapApplication } from '@angular/platform-browser';
import { provideZonelessChangeDetection } from '@angular/core';
import { provideThlUI } from '@thl-ui/angular';
bootstrapApplication(AppComponent, {
providers: [
provideZonelessChangeDetection(),
provideThlUI({ locale: 'zh', theme: 'green', persist: true, components: { Table: { pageSize: 25 } } }),
],
});在 angular.json 中添加 CSS → styles: ["node_modules/@thl-ui/styles/dist/thl-ui.css"]。
导入组件
按需导入,或使用 THL_UI 一次性导入全部:
ts
import { ThlButtonComponent, ThlCardComponent, ThlTranslatePipe, THL_UI } from '@thl-ui/angular';
@Component({
selector: 'app-demo',
imports: [ThlButtonComponent, ThlCardComponent, ThlTranslatePipe], // 或:imports: [THL_UI]
template: `
<thl-card [title]="'menu.dashboard' | thlT">
<button thl-button variant="primary" icon="download">下载</button>
</thl-card>`,
})
export class DemoComponent {}按钮和输入框是挂在原生元素上的属性组件(attribute component)(button[thl-button]、a[thl-button]、input[thlInput]、table[thlTable]),因此保留了原生语义、表单行为和无障碍特性。
服务
| 服务 | 用途 |
|---|---|
ThlConfigService | config() signal、set(patch)、prefix()、defaults(name, props) |
ThlI18nService | t()、n()、d()、locale() signal、setLocale() |
ThlToastService | success/info/warning/error/show/dismiss |
ThlModalService | confirm(options): Promise<boolean> |
管道(pipe):{{ 'common.save' | thlT }} · {{ 'pagination.total' | thlT: { count: n } }}。
双向绑定与表单
每个控件都实现了 ControlValueAccessor,_并且_暴露一个 signal model,因此三种写法都可用:
html
<thl-select [(value)]="country" [options]="countries" />
<thl-select [(ngModel)]="country" [options]="countries" />
<thl-select formControlName="country" [options]="countries" />Reactive Forms 校验使用相同的核心规则,i18n 错误信息由 thl-field 渲染:
ts
import { thlValidators, rules } from '@thl-ui/angular';
form = new FormGroup({
email: new FormControl('', thlValidators(rules.required(), rules.email())),
});html
<thl-field [label]="'pages.login.email' | thlT" for="email" required [control]="form.controls.email">
<input thlInput id="email" formControlName="email" />
</thl-field>内容投影
模板取代了 React 的 render props / Vue 的作用域插槽:
html
<thl-tabs [items]="tabs" [(active)]="tab">
<ng-template thlTab="home"><p>首页</p></ng-template>
<ng-template thlTab="profile"><p>个人资料</p></ng-template>
</thl-tabs>
<thl-data-table [data]="rows" [columns]="cols" rowKey="id">
<ng-template thlCell="salary" let-row>{{ row.salary | currency }}</ng-template>
</thl-data-table>路由(AppLayout)
html
<thl-app-layout [menu]="menu" [currentPath]="path()" [user]="user">
<ng-template thlMenuLink let-item let-cls="cls" let-content="content">
<a [routerLink]="item.href" [class]="cls"><ng-container [ngTemplateOutlet]="content" /></a>
</ng-template>
<router-outlet />
</thl-app-layout>