angular

框架

angular/angular

基于 TypeScript 的 Web 应用开发框架。

项目简介

Angular 是现代的、开源的 Web 应用框架,提供组件、表单、路由和服务端渲染等完整工具集,用于构建移动端和桌面端的 Web 应用。

README 预览

Angular - The modern web developer's platform\n\n\n  \n  \n  Angular is a development platform for building mobile and desktop web applications\n     using TypeScript/JavaScript and other languages.\n  \n\n\n\n  angular.dev\n  \n\n\n\n  Contributing Guidelines\n  ·\n  Submit an Issue\n  ·\n  Blog\n  \n  \n\n\n\n  \n    \n  \n\n\n\n\n## Documentation\n\nGet started with Angular, learn the fundamentals and explore advanced topics on our documentation website.\n\n- [Getting Started][quickstart]\n- [Architecture][architecture]\n- [Components and Templates][componentstemplates]\n- [Forms][forms]\n- [API][api]\n\n### Advanced\n\n- [Angular Elements][angularelements]\n- [Server Side Rendering][ssr]\n- [Schematics][schematics]\n- [Lazy Loading][lazyloading]\n- [Animations][animations]\n\n### Local Development\n\nTo contribute to the Angular Docs, check out the [Angular.dev README](adev/README.md)\n\n## Development Setup\n\n### Prerequisites\n\n- Install [Node.js] which includes [Node Package Manager][npm]\n\n### Setting Up a Project\n\nInstall the Angular CLI globally:\n\n```\nnpm install -g @angular/cli\n```\n\nCreate a workspace:\n\n```\nng new [PROJECT NAME]\n```\n\nRun the application:\n\n```\ncd [PROJECT NAME]\nng serve\n```\n\nAngular is cross-platform, fast, scalable, has incredible tooling, and is loved by millions.\n\n## Quickstart\n\n[Get started in 5 minutes][quickstart].\n\n## Ecosystem\n\n\n  \n\n\n- [Angular Command Line (CLI)][cli]\n- [Angular Material][angularmaterial]\n\n## Changelog\n\n[Learn about the latest improvements][changelog].\n\n## Upgrading\n\nCheck out our [upgrade guide](https://angular.dev/update-guide/) to find out the best way to upgrade your project.\n\n## Contributing\n\n### Contributing Guidelines\n\nRead through our [contributing guidelines][contributing] to learn about our submission process, coding rules, and more.\n\n### Want to Help?\n\nWant to report a bug, contribute some code, or improve the documentation? Excellent! Read up on ou

常见问题 (5)

故障排除
为什么 Angular @if、@for 或 @switch 块中的 SVG 会进入默认的 ng-content 插槽,而不是匹配 select="svg"?

这是一个 Angular 编译器缺陷,影响作为控制流块根节点的 SVG 或 MathML 元素。Angular 会生成带命名空间的标签(如 :svg:svg),因此无法匹配 ng-content 的标签选择器(如 select="svg"),该元素会被投影到默认插槽中。

变通方法:在根 SVG 或 MathML 元素上添加 ngProjectAs:

@if (saving()) {
  <svg class="spinner" ngProjectAs="svg">...</svg>
} @else {
  <svg ngProjectAs="svg">...</svg>
}

对于 MathML,使用:

<math ngProjectAs="math">...</math>

同样的变通方法也适用于 @for、@switch 和 *ngIf 的根节点。属性选择器和类选择器不受影响。Angular 编译器 PR 中已提供永久修复;一旦包含该修复的版本发布,请升级 Angular。

来源 Issue #71162
故障排除
为什么升级到 Angular 22 后,Angular 库组件在 Storybook、Jest、Vitest 或 TestBed 中停止重新渲染(视图空白/过期)?

原因:Angular 22 的 JIT 路径(ɵɵngDeclareComponent → convertDeclareComponentFacadeToMetadata)会忽略声明的库版本,并将 changeDetection 默认设为 OnPush;而 AOT linker 则正确地将使用 Angular < 22 编译的组件保持为 Default/Eager。在 v22 之前以 partial 模式编译的库(例如使用 Angular 20.3 编译的 Kendo UI for Angular)可能会在订阅内部给状态赋值而不调用 markForCheck(),因此在基于 JIT 的工具(Storybook、jest-preset-angular、Vitest、TestBed、ng serve --aot=false)中视图永远不会刷新,而 AOT 构建则工作正常。临时解决方案:在任何库声明被求值之前为 JIT 编译器 facade 打补丁(例如,在 Storybook preview 配置或测试设置文件中):

import '@angular/compiler';
import { ChangeDetectionStrategy } from '@angular/core';

const facade = (globalThis as any).ng?.ɵcompilerFacade;
const original = facade.compileComponentDeclaration.bind(facade);
facade.compileComponentDeclaration = (env: unknown, url: string, decl: any) => {
  const major = Number.parseInt(String(decl.version ?? '0').split('.')[0], 10);
  const patched =
    decl.changeDetection == null && major > 0 && major < 22
      ? { ...decl, changeDetection: ChangeDetectionStrategy.Eager }
      : decl;
  return original(env, url, patched);
};

或者,在库的组件中显式设置 changeDetection: ChangeDetectionStrategy.Default,并使用 Angular 22 重新发布。修复进展可在 angular/angular#71107 跟踪。

来源 Issue #71107
故障排除
为什么在使用 withI18nSupport() 时,ICU 复数文本在 Angular SSR 水合(hydration)后会出现重复?

这是一个已知的 Angular bug(issue #71425),影响 provideClientHydration(withI18nSupport())。当同一个包含 ICU 表达式(例如 {count, plural, ...})的组件在页面中出现多次时,服务器会对 hydration 数据进行去重,导致两个实例共享同一个 ngh 对象。随后客户端会通过 shift() 修改这个共享的 ICU case 队列,因此只有第一个实例能够正确 hydrate——后续实例会将 ICU 内容渲染两次(生产环境),或者抛出 ASSERTION ERROR: expected matching nodeType [Expected=> 8 == 3 <=Actual](开发模式)。

**变通方案:** 用控制流和独立的 i18n 消息替换 ICU 表达式:

@if (count === 1) {
  <ng-container i18n>1 item</ng-container>
} @else {
  <ng-container i18n>{{ count }} items</ng-container>
}

这样可以完全避开共享的 ICU case 队列。该 bug 存在于 Angular 18.2 到至少 21.2/22.x 版本中,因此升级版本并无帮助——在修复发布之前请使用该变通方案(提议的修复方式是使用 [...caseQueue] 复制 case 队列,而不是修改共享的序列化数据)。

来源 Issue #71425
故障排除
如何在绑定 iframe src 时修复 Angular NG0904 "Unsafe value used in a resource URL context" 错误?

当普通字符串被绑定到资源 URL 属性(如 <iframe [src]>)时,会发生 NG0904。对于资源 URL 而言,调用 sanitize(SecurityContext.URL, url) 是不够的;Angular 要求使用显式信任的 SafeResourceUrl。

使用 bypassSecurityTrustResourceUrl 修复:

import { Component, inject } from '@angular/core';
import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser';

@Component({
  selector: 'app-root',
  template: `<iframe [src]="trustedUrl"></iframe>`,
})
export class App {
  readonly url = 'data:image/svg+xml;base64,...';
  private readonly sanitizer = inject(DomSanitizer);
  readonly trustedUrl: SafeResourceUrl =
    this.sanitizer.bypassSecurityTrustResourceUrl(this.url);
}

仅对你信任的 URL 使用此方法,尤其是 data: URL 或用户提供的 URL。对于不受信任的输入,请根据允许列表进行验证,或者不要将其绑定到资源 URL。

来源 Issue #71092
故障排除
如何修复 Angular DevTools 在嵌套路由中将 home 根路由显示为激活状态的问题?

这是一个已知的 Angular DevTools 路由高亮显示 bug:当查看诸如 /posts/1 的嵌套 URL 时,根路由 / 会被错误地标记为激活状态,尽管它并非当前激活的路由。该问题已在 angular/angular#65037 中修复。

解决方法:
1. 更新 Angular DevTools 浏览器扩展。
- Chrome/Edge:打开 chrome://extensions,启用开发者模式,点击**更新**,然后重新打开 DevTools。
- Firefox:在 about:addons 中更新 Angular DevTools。
2. 如果在本地运行 DevTools,请拉取最新代码并重新构建:

git pull origin main
   npm install
   npm start

或者,cherry-pick 或合并 PR #65037。

无需对应用程序的路由进行任何更改。在更新之前,请将 / 上显示的激活徽标视为纯显示层面的 bug,并使用 Router.url 或路由事件来验证当前路由。

来源 Issue #63493