如何在角度 5 中添加规范链接

问题描述 投票:0回答:6

如何在 Angular 5 中动态添加规范链接

<link rel="canonical" href="http://foobar.com/gotcah"/>
angular angular5 meta-tags canonical-link
6个回答
29
投票

面对同样的问题,我四处搜索并找到了有关如何执行此操作的指南:

https://www.concretepage.com/angular/angular-title-service-and-canonical-url

虽然它使用的是 Angular 6,但我认为它向后兼容 5.

它基本上建议创建一个服务(SEOService),以便在注入的任何地方创建规范链接。它将 Angular

DOCUMENT
对象注入到服务中,并将规范链接元素创建为
HTMLLinkElement
.

注意解决方案是预渲染/服务器端渲染友好的——所以如果你想更好地控制应用程序页面的 SEO,我相信这就是你想要的。

这里是对文章中服务的最小重写:

seo.service.ts

import { Injectable, Inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';

@Injectable({
  providedIn: 'root'
})
export class SeoService { 
   
  constructor(@Inject(DOCUMENT) private doc) {}
  
  createLinkForCanonicalURL() {
     let link: HTMLLinkElement = this.doc.createElement('link');
     link.setAttribute('rel', 'canonical');
     this.doc.head.appendChild(link);
     link.setAttribute('href', this.doc.URL);
   }
} 

这里是使用服务的组件的重写:

data.component.ts

import { Component, OnInit } from '@angular/core';
import { SeoService } from './seo.service';

@Component({
  selector: 'app-data',
  templateUrl: './data.component.html'
})
export class DataComponent implements OnInit {
  
  constructor(private seoService: SeoService) { }
  
  ngOnInit() {
    this.createLinkForCanonicalURL();
  }
  
  createLinkForCanonicalURL() {
    this.seoService.createLinkForCanonicalURL();
  } 
}

您可以简单地让

createLinkForCanonicalURL()
方法采用您希望作为页面规范参考的 URL 的可选参数,以实现完全控制。


4
投票

我得到了解决方案, 创建链接服务(例如:link.service.ts)并粘贴以下代码:

import { Injectable, Optional, RendererFactory2, ViewEncapsulation, Inject } from '@angular/core';
import { DOCUMENT } from '@angular/platform-browser';

@Injectable()
export class LinkService {

constructor(
    private rendererFactory: RendererFactory2,
    @Inject(DOCUMENT) private document
) {
}

/**
 * Inject the State into the bottom of the <head>
 */
addTag(tag: LinkDefinition, forceCreation?: boolean) {

    try {
        const renderer = this.rendererFactory.createRenderer(this.document, {
            id: '-1',
            encapsulation: ViewEncapsulation.None,
            styles: [],
            data: {}
        });

        const link = renderer.createElement('link');
        const head = this.document.head;
        const selector = this._parseSelector(tag);

        if (head === null) {
            throw new Error('<head> not found within DOCUMENT.');
        }

        Object.keys(tag).forEach((prop: string) => {
            return renderer.setAttribute(link, prop, tag[prop]);
        });

        // [TODO]: get them to update the existing one (if it exists) ?
        renderer.appendChild(head, link);

    } catch (e) {
        console.error('Error within linkService : ', e);
    }
}

private _parseSelector(tag: LinkDefinition): string {
    // Possibly re-work this
    const attr: string = tag.rel ? 'rel' : 'hreflang';
    return `${attr}="${tag[attr]}"`;
}
}

 export declare type LinkDefinition = {
  charset?: string;
  crossorigin?: string;
  href?: string;
  hreflang?: string;
  media?: string;
  rel?: string;
  rev?: string;
  sizes?: string;
  target?: string;
  type?: string;
} & {
    [prop: string]: string;
};

组件中的导入服务:

import { LinkService } from '../link.service';

constructor(private linkService: LinkService) {

this.linkService.addTag( { rel: 'canonical', href: 'url here'} );
}

请参考以下链接:

https://github.com/angular/angular/issues/15776


4
投票

这适用于 Angular 8 或 9,并将规范 URL 添加到您网站的每个页面。

  1. 创建规范服务:
// shared/canonical/canonical.service.ts


import { Injectable, Inject } from '@angular/core';
import { DOCUMENT } from '@angular/common';

@Injectable({
  providedIn: 'root'
})
export class CanonicalService {
  constructor(@Inject(DOCUMENT) private dom) {}

  setCanonicalURL(url?: string) {
    const canURL = url == undefined ? this.dom.URL : url;
    const link: HTMLLinkElement = this.dom.createElement('link');
    link.setAttribute('rel', 'canonical');
    this.dom.head.appendChild(link);
    link.setAttribute('href', canURL);
  }
}
  1. 引用规范服务并在应用程序组件中调用它
// app.component.ts
import { CanonicalService } from './shared/services/canonical/canonical.service';
...

ngOnInit() {
  this.canonicalService.setCanonicalURL();
}
...


3
投票

如果您想动态添加规范链接,请创建一个简单的 moveToHead 指令,如下所示:

@Directive({
  selector: '[appMoveToHead]'
})
export class MoveToHeadDirective implements OnDestroy, OnInit {

  constructor(private renderer: Renderer2, 
              private elRef: ElementRef, 
              @Inject(DOCUMENT) private document: Document) {

  }

ngOnInit(): void {
    this.renderer.appendChild(this.document.head, this.elRef.nativeElement);
    this.renderer.removeAttribute(this.elRef.nativeElement, 'appmovetohead');
  }

  ngOnDestroy(): void {
    this.renderer.removeChild(this.document.head, this.elRef.nativeElement);
  }
}

在这里,当用户导航到另一个页面时,我们将从 DOM 中删除规范标签。我们在 MoveToHead 指令的

ngOnDestroy()
中执行此操作。因此,处理了新页面中存在先前规范标签的情况。

用法: 在任何组件中。ts

canonicalLink:string;
constructor(private sanitizer: DomSanitizer) { }
//In oninit or when your data is ready, generate canonical link
ngOnInit() {

    this.blogsService.getBlog(this.blogId).subscribe(data => {
       let canLink = "https://example.com/blog/"+data.blogId;
       // You can use pipe for sanitizing but lets do it here
       this.canonicalLink = this.sanitizer.bypassSecurityTrustResourceUrl(canLink);
    });
}

在任何 component.html 模板中:

<div *ngIf="canonicalLink">
  <link  rel="canonical" appMoveToHead [attr.href]="canonicalLink" />
</div>

<div>
  <!-- Other template html -->
</div>

通过这种方式,您可以使用数据绑定和所有其他内容,并像对待模板中的任何其他元素一样对待

meta
link
等。 例如-

<link rel="amphtml" moveToHead [attr.href]="ampUrl">

此方法也适用于 Angular Universal (SSR)。

请参考以下链接-

https://github.com/angular/angular/issues/15776


1
投票

要销毁现有链接,请在创建新链接之前调用它:

destroyLinkForCanonicalURL() {
    const els = this.document.querySelectorAll('link[rel=\'canonical\']');
    for (let i = 0, l = els.length; i < l; i++) {
      const el = els[i];
      el.remove();
    }
  }

this解决方案完美结合。

它还可以防止在 SSR 模式下重复链接。


0
投票

在 Angular 中动态添加带有 rel="canonical" 的链接标签。这是一个示例,说明如何修改 CanonicalService 以使用 DOCUMENT.URL 获取当前 URL 并使用它来添加规范链接标记

从'@angular/common'导入{文档}; 从 '@angular/core' 导入 { Inject, Injectable };

@Injectable({
  providedIn: 'root'
})
export class CanonicalService {

  constructor(@Inject(DOCUMENT) private document: Document) { }

  addCanonicalUrl(): void {
    const canonicalUrl = this.document.URL;
    const canonicalElement = this.document.querySelector('link[rel="canonical"]');
    if (canonicalElement) {
      canonicalElement.setAttribute('href', canonicalUrl);
    } else {
      const link = this.document.createElement('link');
      link.setAttribute('rel', 'canonical');
      link.setAttribute('href', canonicalUrl);
      this.document.head.appendChild(link);
    }
  }
}

这是一个更新的 HomeComponent,它使用 CanonicalService 添加规范链接标签:

import { Component, OnInit } from '@angular/core';
import { Meta, Title } from '@angular/platform-browser';
import { CanonicalService } from './canonical.service';

@Component({
  selector: 'app-home',
  templateUrl: './home.component.html',
  styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {

  constructor(
    private title: Title,
    private meta: Meta,
    private canonicalService: CanonicalService
  ) { }

  ngOnInit(): void {
    this.canonicalService.addCanonicalUrl();

    this.title.setTitle('Home Page');
    this.meta.addTag({ name: 'description', content: 'This is the home page.' });
  }

}

在这个版本的 HomeComponent 中,我们使用 CanonicalService 添加规范链接标签,并使用 DOCUMENT.URL 获取当前 URL。

© www.soinside.com 2019 - 2024. All rights reserved.