【问题标题】:Angular replace html content with a link to a page fragmentAngular用指向页面片段的链接替换html内容
【发布时间】:2018-07-02 21:26:16
【问题描述】:

我有一个在页面上输出 cmets 的组件。在这些 cmets 中,有一些 HTML <footer>By John Doe on Jan 23, 2018</footer>

我正在尝试将页脚的内容包装在 anchor link 中,以便您可以跳转到同一页面上的父通信。

组件 HTML:

<p [innerHTML]="linkComm(comm.Communication, comm)"></p>

comm.communication = Blah Blah Blah &lt;footer&gt;By John Doe on Jan 23, 2018&lt;/footer&gt;

组件 TS:

    /**
     * Link to parent communication
     * @param message 
     * @param comm 
     */
    linkComm(message, comm){
        let output = message;
        output = output.replace(/<footer>/gi, '<footer><a (click)="someMethod(comm.CommunicationID)">');
        output = output.replace(/<\/footer>/gi, '</a></footer>');
        return output;
    }

当我采用这种方法时,不会像我预期的那样将click 事件添加到链接中。

我还尝试了此处建议的模块 (https://stackoverflow.com/a/46587554/2628921),该模块用于页面滚动,但似乎也没有在此处添加 pageScroll

output = output.replace(/&lt;footer&gt;/gi, '&lt;footer&gt;&lt;a pageScroll href="#commID_'+comm.CommunicationID+'"&gt;');

这是一个安全问题,只能将某些属性添加到链接中吗?

【问题讨论】:

  • 我可能是错的,但我不认为这是可能的......据我所知,简单来说,模板通过 Angular 以一种不可能“将 DOM 元素传递给它”通过一些字符串...这不是 jQuery :P 做它的角度风格!
  • @LaurentSchwitter - 我还能怎么做?我通过使用路由器链接尝试了角度方式,但它也与您提到的情况相同,将某些内容传递给元素。 output = output.replace(/&lt;footer&gt;/gi, '&lt;footer&gt;&lt;a [routerLink]="[\'routeexample1\']" fragment="info"&gt;');
  • 为什么不直接创建一个评论组件,它会以更 Angular 的方式自行完成,而不是替换内部 HTML?
  • @SBB 天哪,请不要使用路由器来实现链接:P 执行 Amit 建议的操作...或者干脆 [(click)]="hasLink ? 'linkID' : ''" 或一些东西...我强烈建议您阅读一些有角度的文档...在我看来,您似乎没有,并且正在尝试使它像没有角度一样工作...按照一些快速入门指南或教程来维护您自己的福祉

标签: javascript angular typescript


【解决方案1】:

Angular 已预编译

请记住,Angular 是预编译的。 Angular 模板语法在编译时被消耗和转换,这意味着 DOM 不会主动检查 Angular 语法。事实上,Angular 的一个目标是将代码与 DOM 分离。

这样想:向元素添加(click) 不是有效的普通 HTML 语法。当您将该绑定添加到 Angular 项目中的模板、编译它并通过您的 DevTools 检查输出时,(click) 属性将不再位于已编译 HTML 中的元素上。这是因为 Angular 编译器识别出 (click) 语法,将其从输出的 HTML 中删除,而是在后台注册一个 onclick 处理程序,该处理程序在分配的范围内的行为与您期望的一样,并且 Angular 在其自己的空间。一旦它被编译为一个组件,简单地改变 HTML 就不会添加任何 Angular 会意识到的东西——逻辑就在那里,但它已被 框架使用。

原始 HTML

现在,Angular 用模板语法的这种想法大放异彩,但是在处理原始 HTML 时,使用“Angular 方式”可能会有点棘手。理想的解决方案是根本不解析原始 HTML,但我会假设您的情况是必要的。

由于 Angular 将 DOM 封装在其 API 中,因此不直接操作它被认为是最佳实践(注意:将可能昂贵的函数调用绑定到输入也可能很糟糕……在更改检测周期中调用)。您可以尝试一下:

<app-link-comm [comm]="comm"></app-link-comm>

app-link-comm 是一个组件:

@Component({
  selector: 'app-link-comm',
  template: '<p [innerHTML]="comm.Communication"></p>`,
  styles: {some-style: stylish}
})
export class LinkCommComponent implements AfterViewInit {

  // Allow the parent to bind a comm to the component
  @Input('comm') comm;


  constructor(public render: Renderer2, public router: Router) {}

  // Wait until afterViewInit so the view is drawn and inputs are resolved
  ngAfterViewInit() {
    // Search within this node with a jQuery-like DOM querySelector
    let footer = this.renderer.selectRootElement('footer');
    // attach some Angular-aware behavior to it
    this.renderer.listen(footer, 'click', (event: Event) => {
      // do whatever you want on click here. We could emit an event that the parent component could listen to, but let's just assume we're changing routes and act on the router directly.
      this.router.navigate(`#commID_${this.comm.CommunicationId}`);
    }

    /** That leaves us with a click listener on the footer. 
    /* If we wanted to append a child element, we just use the Renderer with the new element:
    **/

    let a = document.createElement('a');
    // We could listen for clicks on the <a> like above, but let's just attach vanilla behavior:
    a.href = `#commID_${this.comm.CommunicationId}`;
    this.renderer.appendChild(footer, a);

  }

}

Renderer2 是一个可注入的服务,它既包含浏览器和移动 API 的差异,也允许我们将行为附加到 Angular 可以通过其NgZone 管理的元素。

或者:

如果您想使用href 将锚元素附加到页脚 使用指令、管道甚至动态呈现的组件都可能实现相同的目标,但我认为在处理原始 HTML 时这是一个很好的解决方案。该组件有一个单一的绑定,[innerHTML] 允许 Angular 清理输入,并且 DOM 查询是通过 Angular Renderer 完成的,而不是手动解析。

由于现在这是它自己的组件,因此也可以在此处保留其他本地化行为。

就向原始 HTML 添加指令而言,这是不可能的。 Angular 需要在编译前了解该指令以正确附加其行为。最好的办法是制作一个带有指令的宿主组件/元素,然后将正确的(解析的)html 元素绑定到该元素。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-27
    • 2018-10-07
    • 2015-10-05
    • 2010-10-03
    • 2017-01-12
    • 2010-11-27
    相关资源
    最近更新 更多