安装依赖
"bytemd": "^1.9.2",
"@bytemd/plugin-breaks": "^1.10.6",
"@bytemd/plugin-footnotes": "^1.10.6",
"@bytemd/plugin-frontmatter": "^1.10.6",
"@bytemd/plugin-gemoji": "^1.10.6",
"@bytemd/plugin-gfm": "^1.10.6",
"@bytemd/plugin-highlight": "^1.10.6",
"@bytemd/plugin-math": "^1.10.6",
"highlightjs": "^9.16.2",
"@bytemd/plugin-medium-zoom": "^1.10.6",
"@bytemd/plugin-mermaid": "^1.10.6",
修改TypeScript配置
不修改的话,angular的配置不兼容bytemd,因为bytemd用的sevelte
{
"compilerOptions": {
"skipLibCheck": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true
}
}
自定义代码高亮插件
export default function highlightStyle() {
let cacheHL = 'a11y-dark';
return {
viewerEffect({file}) {
// 这里file就是刚才挂载了frontmatter的那个对象
const hl = file?.frontmatter?.highlight; // hl = 'a11y-dark'
if (cacheHL === hl) {
return () => {
};
}
cacheHL = hl || cacheHL;
const $style = document.createElement('link');
// 从styleList获取到'a11y-dark'样式插入到head中
$style.rel = 'stylesheet';
$style.type = 'text/css';
$style.href = `assets/code-styles/${cacheHL}.css`;
document.head.appendChild($style);
return () => {
$style.remove()
}
},
actions: []
}
}
封装editor组件
import {AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, OnInit, ViewChild} from '@angular/core';
import {Editor} from 'bytemd';
import breaks from '@bytemd/plugin-breaks';
import footnotes from '@bytemd/plugin-footnotes';
import frontmatter from '@bytemd/plugin-frontmatter';
// import gemoji from '@bytemd/plugin-gemoji';
import gfm from '@bytemd/plugin-gfm';
import highlight from '@bytemd/plugin-highlight';
import math from '@bytemd/plugin-math';
import mediumZoom from '@bytemd/plugin-medium-zoom';
import mermaid from '@bytemd/plugin-mermaid';
import highlightStyle from '../plugin/highlight.plugin';
import {AttachmentService} from '../../../../../src/app/core/service/biz/attachment.service';
import {map} from 'rxjs/operators';
import zh_Hans from 'bytemd/lib/locales/zh_Hans.json';
import gfm_zh_Hans from '@bytemd/plugin-gfm/lib/locales/zh_Hans.json';
import math_zh_Hans from '@bytemd/plugin-math/lib/locales/zh_Hans.json';
import mermaid_zh_Hans from '@bytemd/plugin-mermaid/lib/locales/zh_Hans.json';
@Component({
selector: 'app-md-editor',
template: `
<div #bytemdHost class="bytemd-host"></div>
`,
styleUrls: ['./markdown-editor.component.scss'],
preserveWhitespaces: true,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MarkdownEditorComponent implements OnInit, AfterViewInit {
@ViewChild('bytemdHost') hostRef: ElementRef;
editor: Editor;
markContent: string;
constructor(private attachmentService: AttachmentService) {
}
ngOnInit(): void {
}
ngAfterViewInit(): void {
const plugins = [breaks(),
gfm({locale: gfm_zh_Hans}),
footnotes(),
highlight(),
math({locale: math_zh_Hans}),
mediumZoom(),
mermaid({locale: mermaid_zh_Hans}),
frontmatter(),
highlightStyle()];
this.editor = new Editor({
target: this.hostRef.nativeElement,
locale: zh_Hans,
props: {
plugins,
locale: zh_Hans,
placeholder: '...',
uploadImages: (files: File[]) => {
return this.attachmentService.upload(files).pipe(
map(res => res.map(item => {
return {
url: `/article-server/attachments/download/${item.id}`,
alt: item.name,
title: item.name,
}
})
)
).toPromise();
}
},
});
this.editor.$on('change', (e) => {
this.markContent = e.detail.value;
this.editor.$set({value: e.detail.value});
});
}
getBriefContent(length: number): string {
return this.hostRef.nativeElement.querySelector('.markdown-body').textContent?.substring(0, length);
}
getMarkContent(): string {
return this.markContent;
}
}
自定义viewer组件
import {
AfterViewInit,
ChangeDetectionStrategy,
Component,
ElementRef,
Input,
OnChanges,
OnInit, SimpleChanges,
ViewChild
} from '@angular/core';
import {Editor, Viewer} from 'bytemd';
import breaks from '@bytemd/plugin-breaks';
import footnotes from '@bytemd/plugin-footnotes';
import frontmatter from '@bytemd/plugin-frontmatter';
// import gemoji from '@bytemd/plugin-gemoji';
import gfm from '@bytemd/plugin-gfm';
import highlight from '@bytemd/plugin-highlight';
import math from '@bytemd/plugin-math';
import mediumZoom from '@bytemd/plugin-medium-zoom';
import mermaid from '@bytemd/plugin-mermaid'
import highlightStyle from '../plugin/highlight.plugin';
import gfm_zh_Hans from '@bytemd/plugin-gfm/lib/locales/zh_Hans.json';
import math_zh_Hans from '@bytemd/plugin-math/lib/locales/zh_Hans.json';
import mermaid_zh_Hans from '@bytemd/plugin-mermaid/lib/locales/zh_Hans.json';
@Component({
selector: 'app-md-viewer',
template: `
<div #bytemdHost class="bytemd-host leading-normal text-3xl"></div>
`,
styleUrls: ['./markdown-viewer.component.scss'],
preserveWhitespaces: true,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class MarkdownViewerComponent implements OnInit, AfterViewInit, OnChanges {
@ViewChild('bytemdHost', {static: true}) hostRef: ElementRef;
@Input()
markContent: string;
viewer: Viewer;
constructor() {
}
ngOnInit(): void {
}
ngAfterViewInit(): void {
}
private renderMarkDown(markContent: string) {
const plugins = [breaks(),
gfm({locale: gfm_zh_Hans}),
footnotes(),
highlight(),
math({locale: math_zh_Hans}),
mediumZoom(),
mermaid({locale: mermaid_zh_Hans}),
frontmatter(),
highlightStyle()];
this.viewer = new Viewer({
target: this.hostRef.nativeElement,
props: {
plugins,
value: markContent,
},
});
}
ngOnChanges(changes: SimpleChanges): void {
if (changes.markContent && this.markContent) {
this.renderMarkDown(this.markContent);
}
}
}