这是可能的。我在我的应用程序中实现了它,下面我提供了它是如何制作的描述。
基本思路是使用Meta from @angular/platform-browser
要动态更改特定的元标记,您必须:
- 使用
removeTag(attrSelector: string) : void删除旧的
方法。
- 使用
addTag(tag: MetaDefinition, forceCreation?:
boolean) : HTMLMetaElement 方法添加新的。
当路由器触发路由更改事件时,您必须这样做。
注意:实际上index.html的头部还需要有默认的<title>...</title>和<meta name="description"..." content="..."/>,所以在动态设置之前已经有一些静态内容了。
我的app-routing.module.ts 内容:
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';
import { NgModule } from '@angular/core';
import { RouterModule, Routes, Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import { StringComparisonComponent } from '../module-string-comparison/string-comparison.component';
import { ClockCalculatorComponent } from '../module-clock-calculator/clock-calculator.component';
import { Title, Meta } from '@angular/platform-browser';
const routes: Routes = [
{
path: '', redirectTo: '/string-comparison', pathMatch: 'full',
data: { title: 'String comparison title', metaDescription: 'String comparison meta description content' }
},
{
path: 'string-comparison', component: StringComparisonComponent,
data: { title: 'String comparison title', metaDescription: 'String comparison meta description content' }
},
{
path: 'clock-time-calculator', component: ClockCalculatorComponent,
data: { title: 'Clock time calculator title', metaDescription: 'Clock time calculator meta description content' }
}
];
@NgModule({
imports: [ RouterModule.forRoot(routes) ],
exports: [ RouterModule ]
})
export class AppRoutingModule {
constructor(
private router: Router,
private activatedRoute: ActivatedRoute,
private titleService: Title,
private metaService: Meta
){
//Boilerplate code to filter out only important router events and to pull out data object field from each route
this.router.events
.filter(event => event instanceof NavigationEnd)
.map(() => this.activatedRoute)
.map(route => {
while (route.firstChild) route = route.firstChild;
return route;
})
.filter(route => route.outlet === 'primary')
//Data fields are merged so we can use them directly to take title and metaDescription for each route from them
.mergeMap(route => route.data)
//Real action starts there
.subscribe((event) => {
//Changing title
this.titleService.setTitle(event['title']);
//Changing meta with name="description"
var tag = { name: 'description', content: event['metaDescription'] };
let attributeSelector : string = 'name="description"';
this.metaService.removeTag(attributeSelector);
this.metaService.addTag(tag, false);
});
}
}
- 可以看出,有一个额外的
data 对象字段用于
每条路线。它包含 title 和 metaDescription 字符串
这将用作标题和元标记内容。
- 在构造函数中,我们过滤掉路由器事件并订阅过滤后的事件
路由器事件。那里用的是rxjs,但其实没必要用。常规的
if statements 和loops 可用于流、过滤器和映射。
- 我们还将我们的数据对象字段与我们的事件合并,这样我们就可以轻松地
使用
title 和 metaDescription 字符串等信息。
- 我们动态更改
<title>...</title> 和<meta name="description"..." content="..."/> 标签。
效果:
第一个组件
第二个组件
事实上,我目前使用这个解决方案的更复杂的版本,它还使用ngx-translate 来显示不同语言的不同标题和元描述。
完整代码可在angular2-bootstrap-translate-website-starter 项目中找到。
带有 ngx-translate 解决方案的 app-routing.module.ts 文件就在那里:app-routing.module.ts。
还有使用相同解决方案的生产应用程序:http://www.online-utils.com。
当然,这不是唯一的方法,可能还有更好的方法来做到这一点。但我测试了这个解决方案,它确实有效。
事实上,解决方案与相应帖子中关于更改标题的解决方案非常相似:How to change page title in angular2 router。
Angular 元文档:https://angular.io/docs/ts/latest/api/platform-browser/index/Meta-class.html。事实上,它们的信息量不是很大,我必须试验并研究真正的 .js 代码才能使这种动态元更改生效。