截取Angular 4的外部链接

9

所以我写了一个小应用程序,展示从维基百科获取的一些信息。

这个获取到的HTML中还有链接。

我的目标是:

每次用户点击链接时,我想拦截它并执行自定义行为,而不是默认的浏览器重定向。

内置的Angular httpinterceptor在这里无法工作。我该如何实现这个效果?

代码:

import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class HttpInterceptorService implements HttpInterceptor {

  constructor() {

  }

  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { //HttpSentEvent | HttpHeaderResponse | HttpProgressEvent | HttpResponse<any> | HttpUserEvent<any>> {
    console.assert(true, 'Intercepting Link request!' + request.url);
    return next.handle(request);
  }
}

我可能有什么误解吗?

编辑: 似乎我误解了href和http请求的工作方式。尽管如此,我仍想在我的应用程序中对每个链接点击进行自定义行为。有没有可能拦截这些“事件”?


为什么 HttpInterceptor 能够起作用呢?这是因为当你的应用程序向外部 Web 服务发出请求时,它才会起作用,与应用程序内部、到达或离开应用程序无关。只需在元素上实现 click 绑定而不是 href 即可。 - jonrsharpe
你读到我从维基百科获取了所有信息了吗?所以我从中获取链接,但我不想跟随这些链接,而是仍然希望对它们进行自定义操作。我知道 Http 拦截是错误的,但我该如何实现? - rufreakde
4个回答

14

好的,在搜索了一段时间后,我找到了一个“非Angular”的解决方案: Override default behaviour for link ('a') objects in Javascript

于是我将其创建为一个服务,并将其注入到我的应用程序根组件中。

import { Injectable } from '@angular/core';

@Injectable() export class HrefInterceptorService {

    constructor() {
        document.onclick = this.interceptHref;
    }

    interceptHref(_event) {
        const tEvent = _event || window.event;

        const element = tEvent.target || tEvent.srcElement;

        if (element.tagName === 'A') {

            console.log("intercept!");

            return false; // prevent default action and stop event propagation
        }
    } }

虽然有点取巧,但相对灵活。


奇怪,它应该根据浏览器工作。我用的是Chrome。您可以将“A”更改为“a”或添加一些新内容。此外,这是在Angular 2.x版本中,没有在4.x中进行测试! - rufreakde

3

为了分析目的,我需要跟踪使用[innerhtml]构建的页面中的出站点击。我尝试了很多方法,但答案其实很简单。我只需要检查合适的链接元素的父级几层即可:

public hrefClicked( $event )
{
  let targetElement;

  if( ( $event.srcElement.nodeName.toUpperCase() === 'A') )
      targetElement = $event.srcElement;
  else if( $event.srcElement.parentElement.nodeName.toUpperCase() === 'A' )
      targetElement = $event.srcElement.parentElement;
  else
      return;

  //  console.log( "Found LINK:" );
  //  console.log( targetElement.href );

  if( targetElement.href && !targetElement.href.includes("mydomain"))
    {
     console.log( "OUTBOUND LINK:" + $event.srcElement.href );
    }
 }
<div class="container-fluid" (click)="hrefClicked($event)">
  <div class="row">
    <div class="col-xs-12">
      <div class="article-body" [innerHTML]="article.content"></div>
    </div>
  </div>
</div>  


2
加载新页面不是XHR请求,因此拦截器无法工作。您需要捕获点击事件并阻止传播:
模板:
<a href="//example.com" (click)="myHandler($event)">Click me</a>

组件:

myHandler(event){
  event.preventDefault();

  doSomethingElse();
}

谢谢您的回复,但我是否必须解析从维基百科获取的所有HTML才能这样做?看起来我误解了这个:https://developer.mozilla.org/en-US/Add-ons/WebExtensions/Intercept_HTTP_requests - rufreakde

1

我找到了一个更加 Angular 化的解决方案,使用 @HostListener 拦截打开新标签页的链接。

文档:https://angular.io/api/core/HostListener#description

通过这种更加 Angular 化的实现方式,您可以从 Angular 控制器中访问 this 而不是使用原生方法访问 DOC。

这是具体实现:

  @HostListener('document:click', ['$event'])
  clickout(_event: Event): boolean {
    const event = _event || window.event;
    const element = event.target || event.srcElement;
    // check for links with target "_blank"
    if ('A' === element.tagName && '_blank' === element.target) {
      // do your stuff here with access to the controller methods
      this.myStuff();
      // prevent default action and stop event propagation
      event.stopPropagation();
      event.preventDefault();
      return false;
    }
  }
  
  private myStuff() {
    console.log( "OUTBOUND LINK:" + element.href );
    // open the link in a new TAB
    window.open(element.href, '_blank')
  }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接