根据 Angular 中的路由动态添加元描述
Dynamically add meta description based on route in Angular
我正在使用 Angular 5 构建一个小型宣传册类型的网站。到目前为止,我已经设置好路线,页面标题会根据激活的路线动态变化。我使用此博客上的说明进行了此操作:https://toddmotto.com/dynamic-page-titles-angular-2-router-events
我目前正在 app.module.ts 中存储我的路线和标题:
imports: [
BrowserModule,
RouterModule.forRoot([
{
path: '',
component: HomeComponent,
data: {
title: 'Home'
}
},
{
path: 'about',
component: AboutComponent,
data: {
title: 'About'
}
},
{
path: 'products-and-services',
component: ProductsServicesComponent,
data: {
title: 'Products & Services'
}
},
{
path: 'world-class-laundry',
component: LaundryComponent,
data: {
title: 'World Class Laundry'
}
},
{
path: 'contact',
component: ContactComponent,
data: {
title: 'Contact'
}
},
{
path: '**',
component: NotFoundComponent,
data: {
title: 'Page Not Found'
}
}
])
],
我也想在那里存储我的元描述,如果将它们添加到 data:
下会很容易。
我正在使用以下代码提取该标题数据,该代码已在上面的博客 link 中注明:
ngOnInit() {
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')
.mergeMap((route) => route.data)
.subscribe((event) => {
this.titleService.setTitle(event['title']);
});
}
所以我的问题是,有没有办法使用相同的方法动态设置元描述?如果有一种方法可以将页面标题和元描述功能结合起来,那就太理想了。
我的 Angular 培训非常有限,所以这可能是一个新手问题。我更像是 designer/css/html 那种人。
首先创建一个 SEOService 或类似下面的东西:
import {Injectable} from '@angular/core';
import { Meta, Title } from '@angular/platform-browser';
@Injectable({
provideIn: 'root' // Add this to ensure your SEO service will be app-wide available
})
export class SEOService {
constructor(private title: Title, private meta: Meta) { }
updateTitle(title: string) {
this.title.setTitle(title);
}
updateOgUrl(url: string) {
this.meta.updateTag({ name: 'og:url', content: url })
}
updateDescription(desc: string) {
this.meta.updateTag({ name: 'description', content: desc })
}
}
在组件中注入 SEOService 后(最好是 app.component.ts),在 OnInit 方法中设置元标记和标题
ngOnInit() {
this.router.events.pipe(
filter((event) => event instanceof NavigationEnd),
map(() => this.activatedRoute),
map((route) => {
while (route.firstChild) route = route.firstChild;
return route;
}),
filter((route) => route.outlet === 'primary'),
mergeMap((route) => route.data)
)
.subscribe((event) => {
this._seoService.updateTitle(event['title']);
this._seoService.updateOgUrl(event['ogUrl']);
//Updating Description tag dynamically with title
this._seoService.updateDescription(event['title'] + event['description'])
});
}
然后像这样配置你的路由
{
path: 'about',
component: AboutComponent,
data: {
title: 'About',
description:'Description Meta Tag Content',
ogUrl: 'your og url'
}
},
恕我直言,这是处理元标记的明确方法。您可以更轻松地更新 facebook 和 twitter 特定标签。
Title
and Meta
是在 Angular 4 中引入的提供程序,应该在服务器端和客户端执行此操作。
要创建或更新 title
标签和 description
元标签,它是:
import { Meta, Title } from '@angular/platform-browser';
...
constructor(public meta: Meta, public title: Title, ...) { ... }
...
this.meta.updateTag({ name: 'description', content: description });
this.title.setTitle(title);
Angular 6+ 和 RxJS 6+ 解决方案,用于在路由更改时动态设置标题
If/when你升级到Angular6这就是解决办法
此服务将:
- 在路线更改时更新元标题。
- 可选择出于任何原因覆盖标题。
Create/change 您的 SEO/meta 服务于以下。
import { Injectable } from '@angular/core';
import { Title, Meta } from '@angular/platform-browser';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import { filter, map, mergeMap } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class MetaService {
constructor(
private titleService: Title,
private meta: Meta,
private router: Router,
private activatedRoute: ActivatedRoute
) { }
updateMetaInfo(content, author, category) {
this.meta.updateTag({ name: 'description', content: content });
this.meta.updateTag({ name: 'author', content: author });
this.meta.updateTag({ name: 'keywords', content: category });
}
updateTitle(title?: string) {
if (!title) {
this.router.events
.pipe(
filter((event) => event instanceof NavigationEnd),
map(() => this.activatedRoute),
map((route) => {
while (route.firstChild) { route = route.firstChild; }
return route;
}),
filter((route) => route.outlet === 'primary'),
mergeMap((route) => route.data)).subscribe((event) => {
this.titleService.setTitle(event['title'] + ' | Site name');
});
} else {
this.titleService.setTitle(title + ' | Site name');
}
}
}
导入您的服务并在构造函数中调用它。
app.component.ts
constructor(private meta: MetaService) {
this.meta.updateTitle();
}
这仍然需要像这样格式化路由。
路线file.ts
{
path: 'about',
component: AboutComponent,
data: {
title: 'About',
description:'Description Meta Tag Content'
}
},
希望这对您和其他希望在 Angular 中动态更新 title/meta 的人有所帮助 6.
以下是我项目中的相关部分。 (Angular 2/4)
app-routing.module.ts:
Routes:
... const appRoutes: Routes = [
{
path: 'path1', loadChildren: './path1#path1Module',
data: {
title: '...',
description: '...',
keywords: '...'
}
},
{
path: 'path2', loadChildren: './path2#path2Module',
data: {
title: '...',
description: '...',
keywords: '...'
}
} ...
app.component.ts(或您的 bootstrap 组件):
imports:
// imports
import { Component, OnInit} from '@angular/core';
import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';
import { Title,Meta } from '@angular/platform-browser';
constructor:
// constructor:
constructor(private router: Router,
private route: ActivatedRoute,
private titleService: Title, private meta: Meta) {}
ngOnInit() method:
ngOnInit() {
this.router.events
.filter((event) => event instanceof NavigationEnd)
.map(() => this.route)
.map((route) => {
while (route.firstChild) route = route.firstChild;
return route;
})
.filter((route) => route.outlet === 'primary')
.mergeMap((route) => route.data)
.subscribe((event) => {
this.updateDescription(event['description'], event['keywords'], event['title']);
});
}
method that updates title and meta tags -> called from ngOnInit():
updateDescription(desc: string, keywords: string, title: string) {
this.titleService.setTitle(title);
this.meta.updateTag({ name: 'description', content: desc })
this.meta.updateTag({ name: 'keywords', content: keywords })
this.meta.updateTag({ name: 'og:title', content: title })
this.meta.updateTag({ name: 'og:description', content: desc })
}
希望对您有所帮助。
由于 Angular 页面是在客户端呈现的,爬虫不可能检测到元标记。由于未检测到动态元标记,大多数爬虫在运行时不会执行 javascript。即使对于 Facebook 和 Twitter 也是如此。
需要使用 Angular 通用服务器端渲染 或预渲染服务,例如 prerender.io
编辑:- 我为此找到了一个很好的 youtube 教程。下面是 link,
https://www.youtube.com/watch?v=lncsmB5yfzE
IMO 在 Routes 数组中使用数据(标题、描述等)并不是那么一致,我们可以将所有数据聚合在一个地方。同样在 2021 年,我们可以使用开箱即用的常用 Angular 工具:
seo-sitemap.ts
export const seoSitemap: ISitemapTag[] = [
{ customUrl: '/contact', title: null, description: 'Some description there', image: '/assets/path/to/image' },
{ customUrl: '/about', title: 'custom about title', description: 'Some description about', image: '/assets/path/to/another-image' }
];
export interface ISitemapTag {
customUrl: string;
title: string | null;
description: string | null;
image: string | null;
}
metatags.service.ts:
import { Injectable } from '@angular/core';
import { Meta, MetaDefinition, Title } from '@angular/platform-browser';
@Injectable()
export class MetatagsService {
constructor(private title: Title, private meta: Meta) {}
updateTitle(title: string) {
this.title.setTitle(title);
}
updateTag(tag: MetaDefinition) {
this.meta.updateTag(tag);
}
updateTags(tags: Array<MetaDefinition | null>) {
tags.forEach((tag) => {
tag && this.meta.updateTag(tag);
});
}
}
app.component.ts
import { MetatagsService } from './shared/services/metatags.service';
import { seoSitemap } from './seoSitemap';
constructor() {
this.sub = this.router.events.subscribe((event: Event) => {
if (event instanceof NavigationEnd) {
this.setMetaTags(event);
}
});
}
ngOnDestroy() { this.sub && this.sub.unsubscribe() }
private setMetaTags(event: NavigationEnd) {
const item = seoSitemap.find((i) => event.urlAfterRedirects === i.customUrl);
if (item) {
if (item.title) this.metatagsService.updateTitle(item.title);
this.metatagsService.updateTags([
item.description ? { name: 'description', content: item.description } : null,
item.image ? { name: 'image', content: item.image } : null,
]);
this.metatagsService.updateTag({ property: 'og:url', content: window.location.href });
} else {
this.metatagsService.updateTitle('Common title there');
}
}
我正在使用 Angular 5 构建一个小型宣传册类型的网站。到目前为止,我已经设置好路线,页面标题会根据激活的路线动态变化。我使用此博客上的说明进行了此操作:https://toddmotto.com/dynamic-page-titles-angular-2-router-events
我目前正在 app.module.ts 中存储我的路线和标题:
imports: [
BrowserModule,
RouterModule.forRoot([
{
path: '',
component: HomeComponent,
data: {
title: 'Home'
}
},
{
path: 'about',
component: AboutComponent,
data: {
title: 'About'
}
},
{
path: 'products-and-services',
component: ProductsServicesComponent,
data: {
title: 'Products & Services'
}
},
{
path: 'world-class-laundry',
component: LaundryComponent,
data: {
title: 'World Class Laundry'
}
},
{
path: 'contact',
component: ContactComponent,
data: {
title: 'Contact'
}
},
{
path: '**',
component: NotFoundComponent,
data: {
title: 'Page Not Found'
}
}
])
],
我也想在那里存储我的元描述,如果将它们添加到 data:
下会很容易。
我正在使用以下代码提取该标题数据,该代码已在上面的博客 link 中注明:
ngOnInit() {
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')
.mergeMap((route) => route.data)
.subscribe((event) => {
this.titleService.setTitle(event['title']);
});
}
所以我的问题是,有没有办法使用相同的方法动态设置元描述?如果有一种方法可以将页面标题和元描述功能结合起来,那就太理想了。
我的 Angular 培训非常有限,所以这可能是一个新手问题。我更像是 designer/css/html 那种人。
首先创建一个 SEOService 或类似下面的东西:
import {Injectable} from '@angular/core';
import { Meta, Title } from '@angular/platform-browser';
@Injectable({
provideIn: 'root' // Add this to ensure your SEO service will be app-wide available
})
export class SEOService {
constructor(private title: Title, private meta: Meta) { }
updateTitle(title: string) {
this.title.setTitle(title);
}
updateOgUrl(url: string) {
this.meta.updateTag({ name: 'og:url', content: url })
}
updateDescription(desc: string) {
this.meta.updateTag({ name: 'description', content: desc })
}
}
在组件中注入 SEOService 后(最好是 app.component.ts),在 OnInit 方法中设置元标记和标题
ngOnInit() {
this.router.events.pipe(
filter((event) => event instanceof NavigationEnd),
map(() => this.activatedRoute),
map((route) => {
while (route.firstChild) route = route.firstChild;
return route;
}),
filter((route) => route.outlet === 'primary'),
mergeMap((route) => route.data)
)
.subscribe((event) => {
this._seoService.updateTitle(event['title']);
this._seoService.updateOgUrl(event['ogUrl']);
//Updating Description tag dynamically with title
this._seoService.updateDescription(event['title'] + event['description'])
});
}
然后像这样配置你的路由
{
path: 'about',
component: AboutComponent,
data: {
title: 'About',
description:'Description Meta Tag Content',
ogUrl: 'your og url'
}
},
恕我直言,这是处理元标记的明确方法。您可以更轻松地更新 facebook 和 twitter 特定标签。
Title
and Meta
是在 Angular 4 中引入的提供程序,应该在服务器端和客户端执行此操作。
要创建或更新 title
标签和 description
元标签,它是:
import { Meta, Title } from '@angular/platform-browser';
...
constructor(public meta: Meta, public title: Title, ...) { ... }
...
this.meta.updateTag({ name: 'description', content: description });
this.title.setTitle(title);
Angular 6+ 和 RxJS 6+ 解决方案,用于在路由更改时动态设置标题
If/when你升级到Angular6这就是解决办法
此服务将:
- 在路线更改时更新元标题。
- 可选择出于任何原因覆盖标题。
Create/change 您的 SEO/meta 服务于以下。
import { Injectable } from '@angular/core';
import { Title, Meta } from '@angular/platform-browser';
import { Router, NavigationEnd, ActivatedRoute } from '@angular/router';
import { filter, map, mergeMap } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class MetaService {
constructor(
private titleService: Title,
private meta: Meta,
private router: Router,
private activatedRoute: ActivatedRoute
) { }
updateMetaInfo(content, author, category) {
this.meta.updateTag({ name: 'description', content: content });
this.meta.updateTag({ name: 'author', content: author });
this.meta.updateTag({ name: 'keywords', content: category });
}
updateTitle(title?: string) {
if (!title) {
this.router.events
.pipe(
filter((event) => event instanceof NavigationEnd),
map(() => this.activatedRoute),
map((route) => {
while (route.firstChild) { route = route.firstChild; }
return route;
}),
filter((route) => route.outlet === 'primary'),
mergeMap((route) => route.data)).subscribe((event) => {
this.titleService.setTitle(event['title'] + ' | Site name');
});
} else {
this.titleService.setTitle(title + ' | Site name');
}
}
}
导入您的服务并在构造函数中调用它。
app.component.ts
constructor(private meta: MetaService) {
this.meta.updateTitle();
}
这仍然需要像这样格式化路由。
路线file.ts
{
path: 'about',
component: AboutComponent,
data: {
title: 'About',
description:'Description Meta Tag Content'
}
},
希望这对您和其他希望在 Angular 中动态更新 title/meta 的人有所帮助 6.
以下是我项目中的相关部分。 (Angular 2/4)
app-routing.module.ts:
Routes:
... const appRoutes: Routes = [
{
path: 'path1', loadChildren: './path1#path1Module',
data: {
title: '...',
description: '...',
keywords: '...'
}
},
{
path: 'path2', loadChildren: './path2#path2Module',
data: {
title: '...',
description: '...',
keywords: '...'
}
} ...
app.component.ts(或您的 bootstrap 组件):
imports:
// imports
import { Component, OnInit} from '@angular/core';
import { Router, ActivatedRoute, NavigationEnd } from '@angular/router';
import 'rxjs/add/operator/filter';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';
import { Title,Meta } from '@angular/platform-browser';
constructor:
// constructor:
constructor(private router: Router,
private route: ActivatedRoute,
private titleService: Title, private meta: Meta) {}
ngOnInit() method:
ngOnInit() {
this.router.events
.filter((event) => event instanceof NavigationEnd)
.map(() => this.route)
.map((route) => {
while (route.firstChild) route = route.firstChild;
return route;
})
.filter((route) => route.outlet === 'primary')
.mergeMap((route) => route.data)
.subscribe((event) => {
this.updateDescription(event['description'], event['keywords'], event['title']);
});
}
method that updates title and meta tags -> called from ngOnInit():
updateDescription(desc: string, keywords: string, title: string) {
this.titleService.setTitle(title);
this.meta.updateTag({ name: 'description', content: desc })
this.meta.updateTag({ name: 'keywords', content: keywords })
this.meta.updateTag({ name: 'og:title', content: title })
this.meta.updateTag({ name: 'og:description', content: desc })
}
希望对您有所帮助。
由于 Angular 页面是在客户端呈现的,爬虫不可能检测到元标记。由于未检测到动态元标记,大多数爬虫在运行时不会执行 javascript。即使对于 Facebook 和 Twitter 也是如此。
需要使用 Angular 通用服务器端渲染 或预渲染服务,例如 prerender.io
编辑:- 我为此找到了一个很好的 youtube 教程。下面是 link, https://www.youtube.com/watch?v=lncsmB5yfzE
IMO 在 Routes 数组中使用数据(标题、描述等)并不是那么一致,我们可以将所有数据聚合在一个地方。同样在 2021 年,我们可以使用开箱即用的常用 Angular 工具:
seo-sitemap.ts
export const seoSitemap: ISitemapTag[] = [
{ customUrl: '/contact', title: null, description: 'Some description there', image: '/assets/path/to/image' },
{ customUrl: '/about', title: 'custom about title', description: 'Some description about', image: '/assets/path/to/another-image' }
];
export interface ISitemapTag {
customUrl: string;
title: string | null;
description: string | null;
image: string | null;
}
metatags.service.ts:
import { Injectable } from '@angular/core';
import { Meta, MetaDefinition, Title } from '@angular/platform-browser';
@Injectable()
export class MetatagsService {
constructor(private title: Title, private meta: Meta) {}
updateTitle(title: string) {
this.title.setTitle(title);
}
updateTag(tag: MetaDefinition) {
this.meta.updateTag(tag);
}
updateTags(tags: Array<MetaDefinition | null>) {
tags.forEach((tag) => {
tag && this.meta.updateTag(tag);
});
}
}
app.component.ts
import { MetatagsService } from './shared/services/metatags.service';
import { seoSitemap } from './seoSitemap';
constructor() {
this.sub = this.router.events.subscribe((event: Event) => {
if (event instanceof NavigationEnd) {
this.setMetaTags(event);
}
});
}
ngOnDestroy() { this.sub && this.sub.unsubscribe() }
private setMetaTags(event: NavigationEnd) {
const item = seoSitemap.find((i) => event.urlAfterRedirects === i.customUrl);
if (item) {
if (item.title) this.metatagsService.updateTitle(item.title);
this.metatagsService.updateTags([
item.description ? { name: 'description', content: item.description } : null,
item.image ? { name: 'image', content: item.image } : null,
]);
this.metatagsService.updateTag({ property: 'og:url', content: window.location.href });
} else {
this.metatagsService.updateTitle('Common title there');
}
}