在Angular 21中添加默认查询参数

前端开发 2026-07-11

在Angular 21之前,可以这样添加默认查询参数,以避免在应用的每个链接中都写入它们:

@Directive({
    selector: "[myRouterLink]",
    standalone: false
})
export class MyRouterLinkDirective extends RouterLink {

    @Input()
    set myRouterLink(commands: any[] | string | null | undefined) {
        super.routerLink = commands;
    }

    get urlTree(): UrlTree {
        const { myCustId } = this.activatedRoute.snapshot.queryParams;

        const urlTree = super.urlTree;
        urlTree.queryParams.myCustId = myCustId;
        return urlTree;
    }
}

因此,不再用 routerLink 生成链接,而是在整个应用中使用 myRouterLink。这在用查询参数进行功能开关控制的场景,以及多租户应用场景(每个页面都带有一个customerId的查询参数)中都很有用。

上述代码在Angular的若干版本中一直能正常工作,甚至在Angular 20也可以使用。但在Angular 21中,这个提交 改变了实现方式,尽管 urlTree 仍然存在,它不再被 onClick 调用,相反,onClick 调用 _urlTree,而 _urlTree 被标注为 @internal,因此Angular的编译器不允许我覆盖它:

  • 之前

```typescript @HostListener('click', [ ... ]) onClick( ... ): boolean { const urlTree = this.urlTree; .... }

get urlTree(): UrlTree | null {
   // ... actual implementation here ...
 }

``` * 之后

```typescript @HostListener('click', [ ... ]) onClick( ... ): boolean { const urlTree = this._urlTree(); .... }

get urlTree(): UrlTree | null {
  return untracked(this._urlTree);
}

/** @internal */
_urlTree = computed(() => { 
   // ... actual implementation here ...
})

```

有没有办法在Angular 21中实现默认查询参数功能?

解决方案

我最终使用了 Directive Composition API,它类似于类继承,但仅使用RouterLink公共API,因此除非公共API发生变化,否则未来不太容易出问题:

@Directive({
    selector: "[myRouterLink]",
    standalone: false,
    hostDirectives: [{
        directive: RouterLink,
        // As the functionality of these inputs is not augmented by me, 
        // I can leave the values be pass unmodified from my components
        // to RouterLink.
        inputs: [
            "target", "fragment", "queryParamsHandling", "state", 
            "info", "relativeTo", "preserveFragment", "skipLocationChange",
        ],
    }],
})
export class MyRouterLinkDirective {

    // Gets a hold of the directive that I'm composing
    routerLink = inject(RouterLink);

    private customerId = inject(MyCustomerId);
    private originalQueryParams: Params = {};

    @Input()
    set myRouterLink(commands: any[] | string) {
        this.routerLink.routerLink = commands;
        this.updateQueryParams();
    }

    @Input()
    set queryParams(params: Params) {
        this.originalQueryParams = params || {};
        this.updateQueryParams();
    }

    private updateQueryParams() {
        const newQueryParams = { ...this.originalQueryParams };

        if (this.customerId) {
            newQueryParams.customerId = this.customerId;
        }

        this.routerLink.queryParams = newQueryParams;
    }
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章