Angular 2中的语法高亮显示

时间:2017-04-01 19:55:32

标签: angular syntax-highlighting

我使用角度2创建简单的Web应用程序。我有两个组件。首先是基本上包含一些数据行的表。当执行单击行时,对应于行的数据显示在第二个组件中。数据是XML,加载到代码元素。它看起来像

@Component
export class TableComponent {
    items: Data[];
    selectedItemsXml: string;
    ...other stuff

    //when row is clicked
    toggleSelectedRow(rowIndex: number) {
        ...other stuff related to change row's background color
        this.selectedItemsXml = this.items[i].xml;
    }
    ...other stuff again
}

//TableComponent's template
<div>
    <table>
        ...
        ...*ngFor="let item of items; let i = index;"...
        <tr (click)="toggleSelectedRow(i)">
            <td>{{item.id}}</td>
            <td>{{item.time}}</td>
        </tr>
        ...
    </table>
</div>
<xml-detail [xml]="selectedItemsXml"></xml-detail>

@Component
export class XmlDetailComponent {
    @Input() xml: string;
}

//XmlDetailComponent's template
<div>
    <pre><code>{{xml}}</code></pre>
</div>

一切正常,直到我想为xml添加语法高亮。首先,我想使用插件ng2-prism,但我有问题使其正常工作。在我看到git repo中的问题之后,我把它扔掉了。我接下来尝试的是基于这篇文章使用highlight.js创建指令:highlight.js does not work with Angular 2。使用此方法突出显示Xml,但仅单击第一次行。单击另一行时,甚至不显示新的xml。我也尝试使用prism.js,但我得到了相同的行为。一旦某个xml字符串第一次绑定,显示在代码元素中并使用highlight.js或prism.js突出显示,它仍然存在。

我的猜测是它与DOM和数据绑定在角度2中的工作方式有关,因为不使用语法高亮,我会在每次选择行时绑定并将字符串传递给代码元素。使用突出显示导致绑定字符串,将其传递给代码元素然后预先设置它。这意味着代码元素中没有简单的字符串,但是很多样式化的span元素,在选择新行时会导致加载新xml字符串的问题。我也试图绑定&#34; pre-prettified&#34;使用Prism.highlight(text_to_prettify)的字符串,但使用此方法会导致显示带有Prism添加的所有span元素的xml。

现在,我正在考虑如何解决这个问题。请给我一些推动,我怎么能让它发挥作用。

3 个答案:

答案 0 :(得分:5)

你可以尝试我为Angular 2/4编写的这个简单angular-prism组件,因为ng2-prism不再被维护,并且不适用于最新的角度释放。

答案 1 :(得分:4)

我会创建一个利用prismjs的组件。

包括prismjs脚本,包括您需要的components文件夹中的任何脚本。

<强>的index.html

<link href="node_modules/prismjs/themes/prism.css" rel="stylesheet" />
<script src="node_modules/prismjs/prism.js"></script>
<script src="node_modules/prismjs/components/prism-core.js"></script>
<script src="node_modules/prismjs/components/prism-clike.js"></script>
<script src="node_modules/prismjs/components/prism-csharp.js"></script>

为Prism安装最新的类型定义文件(这将为您提供类型安全性):

npm install @ryancavanaugh/prismjs

注意:不要安装@ types / prismjs - 它要么已过期,要么未正确创作。 prismjs的作者推荐使用@ ryancvanaugh / prismjs作为类型定义。

将文件夹添加到typeRoots中的tsconfig.json列表属性中,以便typescript编译器可以找到它:

tsconfig.json (在compilerOptions下)

"typeRoots": [
  "node_modules/@types",
  "node_modules/@ryancavanaugh"
]

创建一个调用prism的自定义Prism.highlight组件:

<强> prism.component.ts

/// <reference path="../node_modules/@ryancavanaugh/prismjs/prism.d.ts" />
import { 
    Component, 
    AfterViewInit, 
    Input, 
    ElementRef, 
    ViewChild 
} from '@angular/core';

@Component({
    moduleId: module.id,
    selector: 'prism',
    template: `
        <div hidden="true" #rawContent>
            <ng-content></ng-content>
        </div>
        <pre>
            <code [innerHTML]="content">
            </code>
        </pre>

    `
})
export class PrismComponent implements AfterViewInit {
    @Input() language: string;
    @ViewChild("rawContent") rawContent: ElementRef;
    content: string;

    constructor(private elementRef:ElementRef) {
     }

    ngAfterViewInit() {
        this.content = Prism.highlight(this.rawContent.nativeElement.innerHTML, Prism.languages[this.language]);
     }
}

在app.module中声明Prism组件:

<强> app.module.ts

import { NgModule } from '@angular/core';
import { BrowserModule  } from '@angular/platform-browser';
import { HttpModule } from '@angular/http';

import { AppComponent } from './app.component';
import { PrismComponent } from './prism.component';

@NgModule({
    imports: [
        BrowserModule,
        HttpModule        
        ],
    declarations: [AppComponent, PrismComponent],
    providers: [/* TODO: Providers go here */],
    bootstrap: [AppComponent],
})
export class AppModule { }

像这样使用:

<prism language="csharp">
    var x = 3;
    class T
    {{ '{' }}
    {{ '}' }}
</prism>

答案 2 :(得分:0)

我使用PixelBits解决方案,几乎没有任何更改,首先确保您不要在App.component.ts文件中尝试使用prism组件,在检查后,您会看到&#34; View已更改&# 34;如果您重新加载页面,则不会调用错误和ngAfterViewInit()。因此,制作一个基本的路由,一个页面,并在新页面中检查你的prism组件。 接下来,如果您想使用行号插件,Prism.highlight将无法正常工作。您需要使用Prism.highlightElement。 使用PixelBits解决方案,您可以在代码之前和之后获得空白区域。 不要忘记更改参考路径网址,使其与您的项目相匹配。

TS:

export class PrismComponent implements OnInit,AfterViewInit {
    @Input() language: string;
    @ViewChild("rawContent") rawContent: ElementRef;
    @ViewChild("codeRef") codeRef: ElementRef;
    content: string;
    myClass:string;

    constructor(
        private elementRef:ElementRef,
    ) {
    }

    ngOnInit(){
        this.myClass = "language-" + this.language;
    }

    ngAfterViewInit() {
        // trim because ng-content add space
        this.content = this.rawContent.nativeElement.innerHTML.trim();
        // make line number plugin work.
        Prism.highlightElement(this.codeRef.nativeElement,true);
    }
}

和html:

<pre class="line-numbers"><code #codeRef [innerHTML]="content" [class]="myClass"></code></pre>
<div style="display: none;" hidden="true" #rawContent>
  <ng-content></ng-content>
</div>

此外,我没有使用npm来获取prism.js,但是我从官方的棱镜网站上获取了它(行号的插件集成在prism.js中)。