如何在 angular 5 中将指令应用于 innerHtml 中的元素?

How to apply a directive to elements in innerHtml in angular 5?

这适用于 Angular 5 / Ionic 3 应用程序。 我有一个 div,我在其中显示用户从富文本编辑器生成的 html:

<div [innerHtml]='text'></div>

此数据可以包括 <a href> 个链接,我需要为其捕获点击事件以强制在系统的默认浏览器中打开。

我制定了一个指令,它可以完美地用于静态内容,但不会影响 innerHtml 元素内的任何内容。

import { Directive, Input, HostListener } from "@angular/core";
import { InAppBrowser } from "@ionic-native/in-app-browser";

@Directive({
  selector : '[href]'
})
export class PreventLink {

  @Input() href;

  constructor( private iab: InAppBrowser ) {};

  @HostListener('click', ['$event'])
  public onClick( event: Event ) {

    if( event && this.href ) {

      if( this.href.length > 0 ){
        this.iab.create( this.href, '_system' );
      }

      event.preventDefault();
      return false;
    }
  };
};

任何实现我需要的想法都将不胜感激。

如果有人想知道如何做,我会post在这里我的 hacky 解决方案。我仍然希望有更好的 "angular" 解决方案来实现这一目标。

首先,我们需要在 index.html 中准备一个基本的 javascript 代码片段,以找出锚点何时被点击。将其放在该部分的末尾。

<script>
  document.onclick = function (e){
    e = e || window.event || {};
    var element = e.target || e.srcElement;

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

      handleAClick( element.href );

      e.preventDefault();
      return false;
    }
  };

  function handleAClick(){}; //Just a placeholder until the angular app is ready
</script>

然后在 app.component.ts 中,我将用真正的交易覆盖 handleAClick 函数:

import { Component, OnInit, ViewChild } from '@angular/core';
import { InAppBrowser } from '@ionic-native/in-app-browser';
import { Platform } from 'ionic-angular';


@Component({
  templateUrl: 'app.html'
})

export class MySuperApp implements OnInit {

  constructor( private platform: Platform, private iab: InAppBrowser ){};

  ngOnInit() {

    this.platform.ready().then( () => {

      let win = (<any>window);
      win.handleAClick = ( url: string ) => {
        this.handleAClick( url );
      };
    });
  };


  private handleAClick( href: string ) {

    if( href && href.length > 0 ) {
      this.iab.create( href, '_system' );
    }
  };
};

这个 post 已经很老了,但是如果其他人遇到这个问题,我使用几乎相同的自定义指令解决了它,确认此设置对我有用 angular 9 / ionic 5.

import { Directive, HostListener } from '@angular/core';

/**
 * Custom directive so that we can listen for clicks (or taps) on the event detail page.
 * When the user clicks on an embeded link it will be opened by the browser service and now what ever target
 * the link was written for.
 * Since we dont control the content of the event feed descriptions this is the only way we can control
 * what happens when they include a link and the user opens it.
 */
@Directive({
    selector: '[linkInterceptor]',
})
export class LinkIntereptorDirective {

    @HostListener('click', ['$event']) onClick(event: any) {
        this.clickJack(event);
    }

    @HostListener('tap', ['$event']) onTap(event: any) {
        this.clickJack(event);
    }

    private clickJack(event) {
        event.preventDefault();
        if (event.target.tagName.toLowerCase() === 'a') {
            this.open(event.target.href);
        }
    }

    private async open(href) {
        // here you can handle how you want to open the url.
    }

    constructor() { }
}

模板:

<div *ngIf="content.length" class="ion-padding-horizontal" tappable linkInterceptor [innerHtml]="getHtml()"></div>

组件:

  /**
   * For somereason on ionic when you use the pipe syntax to sanitize
   * html it makes the content block not clickable. So this fixes that so we can register our custom link interceptor directive.
   */
  getHtml(): SafeHtml {
    return this.domSanitizer.sanitize(SecurityContext.HTML, htmlContent);
  }