You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Angular+PrismJS组件中清理代码片段的ng-content内容

Cleaning Up ng-content Code in Your Angular Prism Component

Got it, let's tackle how to clean up the ng-content code in your Angular Prism component. The main pain points here are usually unwanted whitespace (like extra indentation from your template), stray line breaks, and HTML special characters that might get parsed instead of showing up as code. Here's a step-by-step solution tailored to your component:

1. First, Understand the Current Flow

Your component currently captures ng-content in a hidden rawContent element, then binds its content to innerHtml. The problem is that ng-content preserves all the whitespace and formatting from where you use the component in your template—so if you indent the code inside <prism>, that extra indent will show up in the rendered code block.

2. Add Content Cleaning Logic

We'll add a few helper functions to clean the raw content before passing it to Prism. Here's how to modify your component:

Step 1: Add Helper Functions

Add these private methods to handle whitespace normalization and HTML escaping (critical if your code includes <, >, or &):

private escapeHtml(unsafe: string): string {
  return unsafe
    .replace(/&/g, "&amp;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;")
    .replace(/'/g, "&#039;");
}

private normalizeWhitespace(rawText: string): string {
  // Trim leading/trailing whitespace
  const trimmed = rawText.trim();
  // Split into lines
  const lines = trimmed.split('\n');
  // Find the minimum indentation across all non-empty lines
  const minIndent = lines
    .filter(line => line.trim() !== '')
    .reduce((min, line) => {
      const indent = line.match(/^\s*/)?.[0].length || 0;
      return Math.min(min, indent);
    }, Infinity);
  // Remove the minimum indent from each line
  return lines.map(line => line.slice(minIndent)).join('\n');
}

Step 2: Update the AfterViewInit Logic

Modify your ngAfterViewInit method to use these helpers to clean the content before highlighting:

ngAfterViewInit(): void {
  // Get the raw text content from the hidden element
  const rawText = this.rawContent.nativeElement.textContent;
  
  // Clean the content: normalize whitespace + escape HTML
  const cleanedText = this.normalizeWhitespace(rawText);
  const escapedText = this.escapeHtml(cleanedText);
  
  // Use Prism to highlight the cleaned text
  this.content = Prism.highlight(escapedText, Prism.languages[this.language], this.language);
  
  // Trigger change detection since we're updating the content property
  this.cdRef.detectChanges();
}

Step 3: Full Modified Component Code

Here's the complete component with all cleanup logic included:

import { Component, AfterViewInit, Input, ElementRef, ViewChild, ChangeDetectorRef } from '@angular/core';
declare var Prism: any;

@Component({
  selector: 'prism',
  template: `
    <div hidden="true" #rawContent>
      <ng-content></ng-content>
    </div>
    <section class="code-container">
      <pre><code [innerHtml]="content" class="block language-{{language}}"></code></pre>
    </section>
  `
})
export class PrismComponent implements AfterViewInit {
  @Input() language: string = 'javascript';
  content: string = '';
  
  @ViewChild('rawContent') rawContent!: ElementRef;
  
  constructor(private cdRef: ChangeDetectorRef) {}

  ngAfterViewInit(): void {
    const rawText = this.rawContent.nativeElement.textContent;
    const cleanedText = this.normalizeWhitespace(rawText);
    const escapedText = this.escapeHtml(cleanedText);
    
    this.content = Prism.highlight(escapedText, Prism.languages[this.language], this.language);
    this.cdRef.detectChanges();
  }

  private escapeHtml(unsafe: string): string {
    return unsafe
      .replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;")
      .replace(/"/g, "&quot;")
      .replace(/'/g, "&#039;");
  }

  private normalizeWhitespace(rawText: string): string {
    const trimmed = rawText.trim();
    const lines = trimmed.split('\n');
    
    const minIndent = lines
      .filter(line => line.trim() !== '')
      .reduce((min, line) => {
        const indent = line.match(/^\s*/)?.[0].length || 0;
        return Math.min(min, indent);
      }, Infinity);
    
    return lines.map(line => line.slice(minIndent)).join('\n');
  }
}

3. Key Benefits of This Approach

  • Whitespace Normalization: Removes extra indentation that comes from nesting the code inside your Angular template, so your code block looks clean.
  • HTML Escaping: Ensures characters like <, >, and & are rendered as code instead of being parsed as HTML, which prevents broken syntax highlighting and unexpected rendering.
  • Preserves Code Structure: Keeps the original line breaks and intentional indentation, so your code remains readable.

4. Optional: Handle Edge Cases

If you need to handle things like trailing spaces or empty lines, you can tweak the normalizeWhitespace function. For example, to remove empty lines entirely:

// Inside normalizeWhitespace, after splitting into lines
const filteredLines = lines.filter(line => line.trim() !== '');
// Then use filteredLines instead of lines for minIndent and joining

内容的提问来源于stack exchange,提问作者Jaime Still

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:22:02