使用 RouterLink 动态添加元素
Add element with RouterLink dynamically
当我将锚元素放在 Angular 组件的某处时,如下所示:
<a [routerLink]="['/LoggedIn/Profile']">Static Link</a>
一切正常。单击 link 时,Angular 路由器导航到目标组件。
现在,我想动态添加相同的 link。在我的应用程序的某个地方,我有一个“通知组件”,它的唯一职责是显示通知。
通知组件做这样的事情:
<div [innerHTML]="notification.content"></div>
其中 notification.content
是 NotificationComponent
class 中的 public 字符串变量,其中包含要显示的 HTML。
notification.content
变量可以包含如下内容:
<div>Click on this <a [routerLink]="['/LoggedIn/Profile']">Dynamic Link</a> please</div>
一切正常并显示在我的屏幕上,但是当我单击动态 link 时没有任何反应 link。
有没有办法让 Angular 路由器与这个动态添加的 link 一起工作?
PS:我知道 DynamicComponentLoader
,但我真的需要一个更不受限制的解决方案,我可以将各种 HTML 发送到我的通知组件,各种不同links.
routerLink
是一个指令。不会为使用 [innerHTML]
添加的 HTML 创建指令和组件。这个 HTML 没有被 Angular 以任何方式处理。
推荐的方法是不使用 [innerHTML]
,而是使用 DynamicComponentLoaderViewContainerRef.createComponent
,将 HTML 包装在一个组件中并动态添加。
有关示例,请参阅
routerLink 无法在内容已经呈现后添加,但您仍然可以达到预期的效果:
用动态数据创建一个href并给它一个class:
`<a class="routerlink" href="${someDynamicUrl}">${someDynamicValue}</a>`
将 HostListener 添加到 app.component 以侦听点击并使用路由器
导航
@HostListener('document:click', ['$event'])
public handleClick(event: Event): void {
if (event.target instanceof HTMLAnchorElement) {
const element = event.target as HTMLAnchorElement;
if (element.className === 'routerlink') {
event.preventDefault();
const route = element?.getAttribute('href');
if (route) {
this.router.navigate([`/${route}`]);
}
}
}
}
自 angular9 起,AOT 是编译 angular 项目的默认推荐方式。
与 JIT 不同,AOT 在运行时不为编译器保留实例,这意味着您无法动态编译 angular 代码。
可以在 angular 9 中禁用 AOT,但不建议这样做,因为你的包大小会更大并且你的应用程序会更慢。
我解决这个问题的方法是在运行时使用渲染器 api 添加点击侦听器,防止 url 的默认行为并调用 angular 路由器
import { Directive, ElementRef, OnDestroy, OnInit, Renderer2 } from '@angular/core';
import { Router } from '@angular/router';
@Directive({
selector: '[hrefToRouterLink]'
})
export class HrefToRouterLinkDirective implements OnInit, OnDestroy {
private _listeners: { destroy: () => void }[] = [];
constructor(private _router: Router,
private _el: ElementRef,
private _renderer: Renderer2) {
}
ngOnInit() {
// TODO how to guarantee this directive running after all other directives without setTimeout?
setTimeout(() => {
const links = this._el.nativeElement.querySelectorAll('a');
links.forEach(link => {
this._renderer.setAttribute(link, 'routerLink', link?.getAttribute('href'));
const destroyListener = this._renderer.listen(link, 'click',
(_event) => {
_event.preventDefault();
_event.stopPropagation();
this._router.navigateByUrl(link?.getAttribute('href'));
});
this._listeners.push({ destroy: destroyListener });
});
}, 0);
}
ngOnDestroy(): void {
this._listeners?.forEach(listener => listener.destroy());
this._listeners = null;
}
}
你可以在这里找到一个例子:https://stackblitz.com/edit/angular-dynamic-routerlink-2
显然上面解释的方法对 JIT 和 AOT 都有效,但是如果你还在使用 JIT 并且想动态编译组件(这可能有助于解决其他问题)。你可以在这里找到一个例子:
https://stackblitz.com/edit/angular-dynamic-routerlink-1
已用资源:
https://indepth.dev/here-is-what-you-need-to-know-about-dynamic-components-in-angular
当我将锚元素放在 Angular 组件的某处时,如下所示:
<a [routerLink]="['/LoggedIn/Profile']">Static Link</a>
一切正常。单击 link 时,Angular 路由器导航到目标组件。
现在,我想动态添加相同的 link。在我的应用程序的某个地方,我有一个“通知组件”,它的唯一职责是显示通知。
通知组件做这样的事情:
<div [innerHTML]="notification.content"></div>
其中 notification.content
是 NotificationComponent
class 中的 public 字符串变量,其中包含要显示的 HTML。
notification.content
变量可以包含如下内容:
<div>Click on this <a [routerLink]="['/LoggedIn/Profile']">Dynamic Link</a> please</div>
一切正常并显示在我的屏幕上,但是当我单击动态 link 时没有任何反应 link。
有没有办法让 Angular 路由器与这个动态添加的 link 一起工作?
PS:我知道 DynamicComponentLoader
,但我真的需要一个更不受限制的解决方案,我可以将各种 HTML 发送到我的通知组件,各种不同links.
routerLink
是一个指令。不会为使用 [innerHTML]
添加的 HTML 创建指令和组件。这个 HTML 没有被 Angular 以任何方式处理。
推荐的方法是不使用 [innerHTML]
,而是使用 DynamicComponentLoaderViewContainerRef.createComponent
,将 HTML 包装在一个组件中并动态添加。
有关示例,请参阅
routerLink 无法在内容已经呈现后添加,但您仍然可以达到预期的效果:
用动态数据创建一个href并给它一个class:
`<a class="routerlink" href="${someDynamicUrl}">${someDynamicValue}</a>`
将 HostListener 添加到 app.component 以侦听点击并使用路由器 导航
@HostListener('document:click', ['$event']) public handleClick(event: Event): void { if (event.target instanceof HTMLAnchorElement) { const element = event.target as HTMLAnchorElement; if (element.className === 'routerlink') { event.preventDefault(); const route = element?.getAttribute('href'); if (route) { this.router.navigate([`/${route}`]); } } }
}
自 angular9 起,AOT 是编译 angular 项目的默认推荐方式。 与 JIT 不同,AOT 在运行时不为编译器保留实例,这意味着您无法动态编译 angular 代码。 可以在 angular 9 中禁用 AOT,但不建议这样做,因为你的包大小会更大并且你的应用程序会更慢。
我解决这个问题的方法是在运行时使用渲染器 api 添加点击侦听器,防止 url 的默认行为并调用 angular 路由器
import { Directive, ElementRef, OnDestroy, OnInit, Renderer2 } from '@angular/core';
import { Router } from '@angular/router';
@Directive({
selector: '[hrefToRouterLink]'
})
export class HrefToRouterLinkDirective implements OnInit, OnDestroy {
private _listeners: { destroy: () => void }[] = [];
constructor(private _router: Router,
private _el: ElementRef,
private _renderer: Renderer2) {
}
ngOnInit() {
// TODO how to guarantee this directive running after all other directives without setTimeout?
setTimeout(() => {
const links = this._el.nativeElement.querySelectorAll('a');
links.forEach(link => {
this._renderer.setAttribute(link, 'routerLink', link?.getAttribute('href'));
const destroyListener = this._renderer.listen(link, 'click',
(_event) => {
_event.preventDefault();
_event.stopPropagation();
this._router.navigateByUrl(link?.getAttribute('href'));
});
this._listeners.push({ destroy: destroyListener });
});
}, 0);
}
ngOnDestroy(): void {
this._listeners?.forEach(listener => listener.destroy());
this._listeners = null;
}
}
你可以在这里找到一个例子:https://stackblitz.com/edit/angular-dynamic-routerlink-2
显然上面解释的方法对 JIT 和 AOT 都有效,但是如果你还在使用 JIT 并且想动态编译组件(这可能有助于解决其他问题)。你可以在这里找到一个例子: https://stackblitz.com/edit/angular-dynamic-routerlink-1
已用资源:
https://indepth.dev/here-is-what-you-need-to-know-about-dynamic-components-in-angular