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

Angular中如何用虚拟化优化pre标签innerHTML的大JSON渲染

解决Angular中大JSON渲染卡顿的虚拟滚动方案

直接把整个美化后的JSON一次性渲染到pre标签的innerHTML里,大数据量时会生成上万DOM节点,必然导致渲染和滚动卡顿。利用Angular CDK的ScrollingModule实现虚拟滚动,只渲染可见区域的行,就能解决这个问题。核心思路是把JSON拆分成单独的行,用虚拟滚动逐行渲染可见部分。

步骤1:改造JSON高亮逻辑,生成行数组

原来的syntaxHighlight返回整个HTML字符串,现在我们需要把JSON拆分成每行,给每行生成对应的高亮HTML:

首先在组件中定义存储高亮行的数组:

highlightedJsonLines: string[] = [];

然后修改处理逻辑,在JSON数据变化时生成行数组(可以放在ngOnChanges或数据加载完成的方法里):

import { SimpleChanges, OnChanges } from '@angular/core';

// 组件要实现OnChanges接口
export class YourComponent implements OnChanges {
  jsonToBeRendered: any; // 你的原始JSON数据
  highlightedJsonLines: string[] = [];

  ngOnChanges(changes: SimpleChanges) {
    // 当JSON数据变化时重新生成高亮行
    if (changes.jsonToBeRendered && this.jsonToBeRendered) {
      this.generateHighlightedLines();
    }
  }

  private generateHighlightedLines() {
    // 格式化JSON为带缩进的字符串
    let json = JSON.stringify(this.jsonToBeRendered, undefined, 2);
    // 转义HTML特殊字符
    json = json.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
    
    // 给JSON元素添加高亮样式
    const highlightedFull = json.replace(
      /(&quot;(\u[a-zA-Z0-9]{4}|\[^u]|[^\&quot;])*&quot;(\s*)?:?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,
      (match) => {
        let cls = 'number';
        if (/^&quot;/.test(match)) {
          cls = /:$/.test(match) ? 'key' : 'string';
        } else if (/true|false/.test(match)) {
          cls = 'boolean';
        } else if (/null/.test(match)) {
          cls = 'null';
        }
        return `<span class="${cls}">${match}</span>`;
      }
    );
    
    // 按换行符拆分成单独的行
    this.highlightedJsonLines = highlightedFull.split('\n');
  }
}

步骤2:用CDK虚拟滚动替换原pre标签

修改HTML模板,使用cdk-virtual-scroll-viewport和*cdkVirtualFor渲染可见行:

<!-- 虚拟滚动容器,设置固定高度 -->
<div class="json-scroll-container">
  <cdk-virtual-scroll-viewport itemSize="18" class="viewport">
    <!-- 逐行渲染高亮后的JSON行 -->
    <pre *cdkVirtualFor="let line of highlightedJsonLines" class="json-line">
      <span [innerHTML]="line"></span>
    </pre>
  </cdk-virtual-scroll-viewport>
</div>

步骤3:添加必要的样式

设置容器高度、虚拟视口样式,同时保留JSON的排版和高亮样式:

/* 虚拟滚动容器,固定高度让滚动生效 */
.json-scroll-container {
  height: 600px;
  border: 1px solid #e0e0e0;
  border-radius: 4px;
}

/* 虚拟视口样式 */
.viewport {
  height: 100%;
  width: 100%;
}

/* 每行的pre样式,保持JSON的空格和缩进 */
.json-line {
  margin: 0;
  padding: 0 8px;
  white-space: pre;
  font-family: 'Consolas', 'Monaco', monospace;
  line-height: 1.2; /* 要和itemSize对应,这里line-height=18px,所以itemSize设18 */
  font-size: 14px;
}

/* JSON高亮样式 */
.json-line .key { color: #6f42c1; }
.json-line .string { color: #28a745; }
.json-line .number { color: #dc3545; }
.json-line .boolean { color: #007bff; }
.json-line .null { color: #ffc107; }

步骤4:导入ScrollingModule

确保在你的Angular模块中导入ScrollingModule:

import { ScrollingModule } from '@angular/cdk/scrolling';

@NgModule({
  imports: [
    // ...其他模块
    ScrollingModule
  ]
})
export class YourModule { }

注意事项

  • itemSize必须和每行的实际高度匹配(比如line-height是18px,就设18),否则虚拟滚动的计算会出错。
  • 如果JSON数据量极大(比如十万行以上),generateHighlightedLines的处理过程可能阻塞主线程,可以考虑将JSON格式化和高亮逻辑放到Web Worker中执行。
  • 保持white-space: pre样式,确保JSON的缩进和空格不会丢失。

内容的提问来源于stack exchange,提问作者Atin Singh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 14:50:23