角度替换HTML内容与页面片段的链接 [英] Angular replace html content with a link to a page fragment

查看:55
本文介绍了角度替换HTML内容与页面片段的链接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个在页面上输出评论的组件.在这些评论中,有一些HTML < footer>由John Doe撰写于2018年1月23日</footer> .

I have a component that is outputting comments on the page. In these comments, there is some HTML <footer>By John Doe on Jan 23, 2018</footer>.

我正在尝试将页脚的内容包装在 anchor链接中,以便您可以跳转到同一页面上的父级通讯.

I am trying to wrap the contents of the footer in an anchor link so that you can jump to the parent communication on the same page.

组件HTML:

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

comm.communication = Blah Blah Blah< footer>由John Doe于2018年1月23日</footer>

组件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 事件添加到链接中.

When I take this approach, no click event is being added to the link like I would expect.

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

I also tried a module suggested here (https://stackoverflow.com/a/46587554/2628921) that is meant for page scrolling but it doest appear that pageScroll is being added on there either.

output = output.replace(/< footer>/gi,'< footer>< pageScroll href =#commID _'+ comm.CommunicationID +'">'));

这是仅可将某些属性添加到链接的安全性问题吗?

Is this a security issue where only certain attributes can be added to a link?

推荐答案

Angular已预编译

请记住,Angular是预编译的.编译时会消耗并转换Angular模板语法,这意味着不会主动检查DOM的Angular语法.实际上,Angular的目标之一就是将您的代码与DOM分离.

Remember, Angular is precompiled. Angular template syntax is consumed and transformed when it is compiled, which means the DOM isn't actively checked for Angular syntax. In fact, one goal of Angular is to decouple your code from the DOM.

这样想:将(单击)添加到元素不是有效的原始HTML语法.将绑定添加到Angular项目中的模板时,对其进行编译,然后通过DevTools检查输出,该(click)属性将不再位于已编译HTML的元素上.这是因为Angular编译器识别出(click)语法,将其从输出的HTML中删除,而是在幕后注册了一个 onclick 处理程序,该处理程序的行为与您期望的相同.它分配的范围,并且Angular在自己的空间中管理此行为.一旦将其编译为组件,只需更改HTML便不会添加Angular会意识到的任何内容-逻辑已经存在,但已被 framework 消耗.

Think of it this way: adding a (click) to an element isn't valid vanilla HTML syntax. When you add that binding to a template in an Angular project, compile it, and inspect the output through your DevTools, that (click) attribute won't be on the element in the compiled HTML anymore. That's because the Angular compiler recognizes that (click) syntax, removes it from the outputted HTML, and instead registers an onclick handler behind the scenes that behaves as you'd expect in the scope it's assigned, and Angular manages this behavior in its own space. Once it's compiled as a component, simply altering the HTML won't add anything that Angular will be aware of -- the logic is there, but it's been consumed by the framework.

现在,Angular充满了模板语法的思想,但是在处理原始HTML时,使用"Angular方式"可能会有些棘手.理想的解决方案是根本不解析原始HTML,但是对于您的情况,我认为这是必要的.

Now, Angular shines with this idea of a template syntax, but when dealing with raw HTML things can be a bit trickier to do 'The Angular way.' The ideal solution would be to not parse raw HTML at all, but I'll assume for your case that it's a necessity.

由于Angular的API中封装了DOM,因此,最好的做法是不直接对其进行操作(注意:将潜在昂贵的函数调用绑定到输入也可能是不好的……在变更检测周期中调用).您可以尝试的替代方法:

Since Angular has the DOM wrapped up in its API, it's considered best practice to not directly manipulate it (note: binding potentially expensive function calls to inputs can also be bad...called on change detection cycles). Something you could try instead:

<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和移动API的差异,还可以使我们将行为附加到Angular可以通过其 NgZone 进行管理的元素上.

The Renderer2 is an injectable service that both wraps up differences in browser and mobile APIs and also allows us to attach behaviors to elements that Angular can manage through its NgZone.

或者:

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

If you wanted to append an anchor element to the footer with an href The same thing could potentially be achieved with directives, pipes, or even dynamically rendered components, but I think this is a good solution when dealing with raw HTML. The component gets a single binding, the [innerHTML] allows Angular to sanitize the input, and DOM querying is done through the Angular Renderer instead of manual parsing.

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

Since this is now its own component, other localized behaviors can be kept here as well.

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

As far as adding directives to raw HTML, it's not going to be possible. Angular needs to be aware of the directive before compile time to attach its behaviors correctly. Your best bet would be to make a host component/element with the directive on it, then bind the correct (parsed) html elements to that element.

这篇关于角度替换HTML内容与页面片段的链接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆