【问题标题】:How to detect async change to ng-content如何检测对 ng-content 的异步更改
【发布时间】:2019-11-23 05:25:23
【问题描述】:

我制作了一个组件,它使用 marked 包来呈现 markdown 内容,问题是当异步事件更改其 ng-content 元素时它不会重新呈现自己。

这是代码

import {Component, ElementRef, AfterContentInit} from 'angular2/core';
declare var marked: any;

@Component({
    selector: 'markdown',
    template:
    '<div style="display:none;">' +
    '    <ng-content></ng-content>' +
    '</div>' +
    '<div class="markdown" [innerHTML]="output"></div>'
})
export class MarkdownComponent implements AfterContentInit {
    output: string;

    constructor(
        private element: ElementRef) {
    }

    ngAfterContentInit() {
        const c = this.element.nativeElement.childNodes;
        this.output = marked(c[0].textContent);
    }
}

这是 HTML sn-p:

<markdown>{{info}}</markdown>

这是异步更新:

updateInfo(text: string) {
    this.svc.update(this.info, text).subscribe(
        data => this.info = data.newText);
}

问题是,当this.svc.update 事件触发时,info 变量的值会发生变化,但markdown 组件不会重新渲染。

谢谢!

分辨率

按照公认答案的建议(感谢 Gunter),这是新组件,它更精简:

import {Component} from 'angular2/core';
declare var marked: any;

@Component({
    selector: 'markdown',
    template: '<div class="markdown" [innerHTML]="process(md)"></div>',
    inputs: ['md']
})
export class MarkdownComponent {
    md: string;

    process(s: string) {
        if (!s) return '';
        return marked(s);
    }
}

这是新的 HTML:

<markdown [md]="info"></markdown>

完美运行! :)

【问题讨论】:

    标签: angular


    【解决方案1】:

    添加@Input() content; 并使用类似的组件

    <markdown [content]="info"></markdown>
    

    会让这更容易。

    或者MutationObserver 应该适用于这个特定的用例。

    【讨论】:

    • 所以ng-content 不是最适合这里的吗? ng-content 有什么好的用例?
    • &lt;ng-content&gt; 在您只想包装组件用户传递的内容时很好。就像在TabComponent 中一样,该组件的用户只提供应该在选项卡中显示的内容,TabComponent 只是根据内容是否在当前选定的选项卡中显示和隐藏它。我不会说 &lt;ng-content&gt; 不适合您的情况。 MutationObserver 很容易使用。
    • 这里是ng-content的使用示例:stackoverflow.com/questions/34950950/…。我同意君特的观点。我认为在你的情况下插值就足够了......
    • MutationObserver 是神送!!1
    • 注意:你需要一个 polyfill 来正确处理 MutationObserver 跨浏览器,但 Universal(服务器端渲染)尚不支持它
    【解决方案2】:

    即使 Günter 的回答很好,我还是忍不住要创建一个小插曲来描述如何在组件中使用 Marked:https://plnkr.co/edit/0oSeaIyMWoq5fAKKlJLA?p=preview。

    详情如下:

    • 标记配置的HTML文件

      <script>
        System.config({
          transpiler: 'typescript', 
          typescriptOptions: { emitDecoratorMetadata: true }, 
          packages: {
            'src': {defaultExtension: 'ts'}
          },
          map: {
            marked: 'https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.5/marked.js'
          }
        });
        System.import('src/boot')
          .then(null, console.error.bind(console));
      </script>
      
    • 使用Marked的组件

      import { Component, Input } from 'angular2/core';
      import marked from 'marked';
      
      @Component({
        selector: 'markdown', 
        template: `
          <div [innerHTML]="convertedData"></div>
        `
      })
      export class MarkdownComponent {
        @Input('data')
        data:string;
      
        ngOnChanges() { 
          this.convertedData = marked(this.data);
        }
      }
      
    • 使用前一个 Markdown 组件的组件

      import { Component } from 'angular2/core';
      import { MarkdownComponent } from './markdown';
      
      @Component({
        selector: 'my-app', 
        template: `
          <div>
            <markdown [data]="markdown"></markdown>
          </div>
        `,
        directives: [ MarkdownComponent ]
      })
      export class AppComponent {
        constructor() {
          this.markdown = 'Hello';
      
          setTimeout(() => {
            this.markdown = `
      # Title
      
      Some __test__
      `;
          }, 1000);
        }
      }
      

    【讨论】:

      猜你喜欢
      • 2018-08-15
      • 1970-01-01
      • 2022-12-22
      • 2019-08-01
      • 1970-01-01
      • 2017-09-28
      • 1970-01-01
      • 1970-01-01
      • 2021-05-31
      相关资源
      最近更新 更多