یکی از موارد مهم بهینه سازی صفحات سایت برای موتورهای جستجو، افزودن عنوانی مناسب، به همراه توضیحات و واژههای کلیدی، twitter card ،Facebook Graph و امثال آنها است. برای این منظور Angular به همراه سرویسهایی است که امکان افزودن این متاتگها را به صورت پویا مهیا میکنند.
آشنایی با امکانات بستهی angular/platform-browser@
در ماژول angular/platform-browser@، دو سرویس Meta و Title، امکان تغییر پویای متاتگهای صفحهی جاری را مهیا میکنند. برای نمونه فرض کنید قصد دارید یک چنین متاتگهایی را به صفحهی جاری اضافه کنید:
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" type="image/x-icon" href="favicon.ico">
<title>newTitle ...</title>
<base href="/">
<meta name="description" content="Angular meta service">
<meta name="author" content="DNT">
<meta name="keywords" content="Angular, Meta Service">
<meta name="twitter:card" content="summary">
<meta name="twitter:site" content="@my_site">
<meta name="twitter:title" content="Front-end Web Development">
<meta name="twitter:description" content="Learn frontend web development...">
<meta name="twitter:image" content="https://site/images/image.png">
<meta name="author" content="Other Author">
</head>
قدم اول انجام اینکار، تزریق سرویسهای توکار Meta و Title به سازندهی کامپوننت جاری است:
import { Component, OnInit } from "@angular/core";
import { Meta, Title } from "@angular/platform-browser";
@Component({
selector: "app-seo-tests",
templateUrl: "./seo-tests.component.html",
styleUrls: ["./seo-tests.component.css"]
})
export class SeoTestsComponent implements OnInit {
constructor(private metaService: Meta, private titleService: Title) {
}
در ادامه متدهای مختلف این سرویسها را بررسی خواهیم کرد:
افزودن یک یا چند متاتگ
متد addTag سرویس Meta، کار افزودن پویای یک متا تگ جدید را به همراه ویژگیهای name و content آن، انجام میدهد. در ذیل چندین مثال از آنرا مشاهده میکنید. در اینجا یا میتوان از متد addTag استفاده کرد که تنها یک متاتگ را به صفحه اضافه میکند و یا از متد addTags کمک گرفت که میتواند آرایهای از متاتگها را به صورت پویا به صفحهی جاری اضافه کند:
// addTag & addTags
this.metaService.addTag({ name: "description", content: "How to optimize your Angular App for search engine and other crawlers." });
this.metaService.addTag({ name: "author", content: "DNT" });
this.metaService.addTag({ name: "keywords", content: "Angular, Meta Service" });
// Or
this.metaService.addTags([
{ name: "description", content: "How to optimize your Angular App for search engine and other crawlers." },
{ name: "author", content: "DNT" },
{ name: "keywords", content: "Angular, Meta Service" }
], false); // --> forceCreation = false
this.metaService.addTag({ name: "twitter:card", content: "summary_large_image" });
this.metaService.addTag({ name: "twitter:site", content: "@my_site" });
this.metaService.addTag({ name: "twitter:title", content: "Front-end Web Development" });
this.metaService.addTag({ name: "twitter:description", content: "Learn frontend web development..." });
this.metaService.addTag({ name: "twitter:image", content: "https://site/images/image.png" });
// Or
this.metaService.addTags([
{ name: "twitter:card", content: "summary_large_image" },
{ name: "twitter:site", content: "@my_site" },
], false); // --> forceCreation = false
هر دو متد addTag و addTags دارای پارامتر boolean دومی به نام forceCreation نیز هستند. برای مثال اگر این پارامتر را به true تنظیم کنید، این متاتگ حتی اگر وجود هم داشته باشد، یکبار دیگر به صفحه اضافه خواهد شد.
دریافت محتوای متاتگهای موجود
با استفاده از متد getTag میتوان یک متاتگ مشخص را به صورت HTMLMetaElement دریافت کرد:
// getTag & getTags
const viewport = this.metaService.getTag("name=viewport");
if (viewport) {
console.log(viewport.content); // width=device-width, initial-scale=1
}
const author = this.metaService.getTag("name=author");
if (author) {
console.log(author.content); // DNT
}
this.metaService.addTag({ name: "author", content: "DNT" });
this.metaService.addTag({ name: "author", content: "Other Author" }, true);
const authors = this.metaService.getTags("name=author");
console.log(authors[0]); // <meta name="author" content="DNT">
console.log(authors[1]); // <meta name="author" content="Other Author">
کار متد getTags بازگشت تمام متاتگهایی با attribute-selector یکسان است. برای مثال در اینجا دوبار متاتگ author به صفحه اضافه شدهاست و خروجی getTags به همراه دو عنصر است.
به روز رسانی متاتگهای موجود
میتوان از متد updateTag برای تغییر محتوای متاتگی موجود، استفاده کرد:
// updateTag
this.metaService.addTag({ name: "twitter:card", content: "summary_large_image" });
this.metaService.updateTag({ name: "twitter:card", content: "summary" }, `name='twitter:card'`);
this.metaService.updateTag({ name: "description", content: "Angular meta service" });
در اینجا اگر پارامتر اختیاری دوم ذکر نشود، جستجوی یافتن عناصر، بر اساس name ذکر شده صورت میگیرد و سپس content آنها به روز میشود.
حذف تگهای موجود
در اینجا میتوان از دو متد removeTag که یک attribute-selector را دریافت میکند و یا removeTagElement که یک HTMLMetaElement را توسط متد getTag دریافت میکند، برای حذف کامل این تگها استفاده کرد:
// removeTag & removeTagElement
this.metaService.removeTag("charset");
// Or
const chartsetTag = this.metaService.getTag("charset");
if (chartsetTag) {
this.metaService.removeTagElement(chartsetTag);
}
تنظیم عنوان صفحهی جاری
سرویس توکار دیگری به نام Title امکان تغییر عنوان صفحهی جاری را به صورت پویا میسر میکند:
// Setting the browser page Title in an Angular app
const currentTitle = this.titleService.getTitle();
console.log(currentTitle);
this.titleService.setTitle("newTitle ...");
متد getTitle، عنوان فعلی صفحه را باز میگرداند و متد setTitle، این عنوان را به روز رسانی میکند.
طراحی سرویسی برای افزودن پویای متاتگها به صفحات مختلف سایت
میتوان شبیه به مطلب «
نمایش Breadcrumbs در برنامههای Angular» به قسمت data مسیریابی، اطلاعات عنوان صفحه و همچنین metaTags آنرا اضافه کرد:
const routes: Routes = [
{
path: "seo", component: SeoTestsComponent,
data: {
title: "Page Title",
metaTags: {
description: "Page Description or some content here",
keywords: "some, keywords, here, separated, by, a comma"
}
}
}
];
سپس سرویسی را طراحی نمود که با پایان یافتن مسیریابی فعلی، این تنظیمات را به صورت خودکار انجام دهد و نیازی نباشد تا مدام به تمام کامپوننتها، سرویسهای Meta و Title را به صورت دستی اضافه کرد و این اطلاعات را تغییر داد.
به همین جهت سرویس SEO را در مسیر src\app\core\seo-service.ts به صورت ذیل ایجاد میکنیم:
import { Injectable } from "@angular/core";
import { Title, Meta } from "@angular/platform-browser";
import { Router, NavigationEnd, ActivatedRouteSnapshot } from "@angular/router";
@Injectable()
export class SeoService {
constructor(private titleService: Title, private metaService: Meta, private router: Router) { }
enableSeo() {
this.router.events
.filter(event => event instanceof NavigationEnd)
.distinctUntilChanged()
.subscribe(() => {
this.addMetaData(this.router.routerState.snapshot.root);
});
}
private addMetaData(root: ActivatedRouteSnapshot): void {
if (root.children && root.children.length) {
this.addMetaData(root.children[0]);
} else if (root.data) {
this.setTitle(root.data);
this.setMetaTags(root.data);
}
}
private setMetaTags(routeData: { [name: string]: any; }) {
const routeDataMetaTagsKey = "metaTags";
const metaTags = routeData[routeDataMetaTagsKey];
if (!metaTags) { return; }
for (const tag in metaTags) {
if (metaTags.hasOwnProperty(tag)) {
const newTag = { name: tag, content: metaTags[tag] };
console.log("new tag", newTag);
this.metaService.addTag(newTag);
}
}
}
private setTitle(routeData: { [name: string]: any; }) {
const routeDataTitleKey = "title";
const title = routeData[routeDataTitleKey];
if (title) {
console.log("new title", title);
this.titleService.setTitle(title);
}
}
}
توضیحات:
در اینجا در ابتدای کار مشترک رخداد NavigationEnd سیستم مسیریابی خواهیم شد:
this.router.events
.filter(event => event instanceof NavigationEnd)
.distinctUntilChanged()
.subscribe(() => {
this.addMetaData(this.router.routerState.snapshot.root);
});
هر زمانیکه رخداد مرور صفحهی جاری به پایان رسید، بر اساس مسیر ریشهی آن، متد addMetaData فراخوانی میشود. این متد، یک متد بازگشتی است. از این جهت که مسیر جاری میتواند حاصل مرور یک مسیر والد و سپس چندین مسیر تو در توی فرزند و والد آن باشد.
سپس در این متد خاصیت data مسیرنهایی را خوانده و کلیدهای title و metaTags آنرا استخراج میکنیم و سپس توسط متدهای this.titleService.setTitle و this.metaService.addTag، این عنوان و متاتگهای جدید را به صورت پویا به صفحه اضافه خواهیم کرد.
پس از تعریف این سرویس، برای معرفی آن به برنامه، ابتدا آنرا به قسمت providers مربوط به CoreModule اضافه میکنیم:
import { SeoService } from "./seo-service";
@NgModule({
providers: [
SeoService
]
})
export class CoreModule {}
و در آخر به فایل app.component.ts مراجعه کرده و این سرویس را فعالسازی میکنیم:
import { SeoService } from "./core/seo-service";
export class AppComponent {
constructor(private seoService: SeoService) {
this.seoService.enableSeo();
}
}
از این پس تمام مسیرهای برنامه به صورت خودکار تحت نظر قرار گرفته و درصورتیکه خاصیت data آنها دارای کلیدهای title و metaTags باشند، به صورت خودکار پردازش خواهند شد.
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید.