代码示例
自定义 markdown 渲染。
diviceMarkdownConfig.js
const defaultConfig = {
name: 'default',
textstyle() {
return [
'color: rgba(255, 255, 255, 0.90)',
'font-size: 30px',
'font-weight: 400',
'line-height: 50px',
].join(';');
},
margin() {
return [
'height: 20px',
].join(';');
},
paragraphMargin() {
return [
'height: 20px',
].join(';');
},
latex() {
return [
'color: rgba(255, 255, 255, 0.90)',
'font-size: 30px',
'line-height: 50px',
'lineSpacing: 16px',
].join(';');
},
code() {
return [
'background-color: #333',
'padding: 6px',
'color: rgba(255,255,255,0.6)',
].join(';');
},
heading: {
h(index) {
const fontSize = 48 - (index - 1) * 6;
const lineHeight = 58 - (index - 1) * 6;
const fontWeight = 900 - (index - 1) * 100;
return [
`font-size: ${fontSize}px`,
`line-height: ${lineHeight}px`,
`font-weight: ${fontWeight}`,
].join(';');
},
hNum(index) {
const fontSize = 48 - (index - 1) * 6;
return [
'color:#578FFF',
`font-size: ${fontSize}px`,
].join(';');
},
margin(index) {
const marginBottom = 28 - (index - 1) * 4;
return [
`height: ${marginBottom}px`,
].join(';');
},
},
hr() {
return [
'height: 1px',
'background-color: rgba(255, 255, 255, 0.16)',
].join(';')
},
blockquote() {
return [
'background-color: #666',
'padding: 6px',
'border-left: 4px solid #333',
'color: rgba(255,255,255,0.6)',
].join(';')
},
list(depth) {
return [
`padding-left:${(depth - 1) * 16}px`,
].join(';');
},
listitem: {
liNum() {
return [
'color: rgba(255,255,255,0.9)',
].join(';');
},
olNum() {
return [].join(';');
},
},
table: {
table() {
return [].join(';');
},
tableCell() {
return [
'border:1px solid red',
'padding: 0 10px',
].join(';');
},
headerCell() {
return [].join(';');
},
bodyCell() {
return [].join(';');
},
},
paragraph() {
return [].join('');
},
strong() {
return [
'font-weight: 700',
].join(';');
},
em() {
return [
'font-style: italic'
].join(';');
},
codespan() {
return [
'color: rgba(255,255,255,0.6)',
].join(';');
},
br() {
return [
'height: 20px',
].join(';');
}
};
const styleConfig = {
a: {
name: 'a',
},
b: {
name: 'b',
},
};
const getConfigByName = (name) => {
let config = { ...defaultConfig };
if (config[name]) {
config = {
...styleConfig[name],
};
}
return config;
};
export {
getConfigBySku,
};
hassmarked.js
import { marked } from "./marked.esm.js";
import { getConfigBySku } from "./diviceMarkdownConfig.js";
const skuConfig = getConfigByName();
const options = {
gfm: true, // 允许 Git Hub标准的markdown
breaks: true, // 单个\n换行,要求 gfm 为true
tables: true, // 允许支持表格语法,要求 gfm 为true
pedantic: false, // 非严格模式:支持表格等扩展语法
sanitize: false, // 会保留并渲染输入中包含的所有 HTML 标签,true 时过滤掉html标签
};
let listDepth = 0;
const renderer = {
// block markdown
code(options) {
const { text } = options;
const style = skuConfig?.code();
const marginStyle = skuConfig?.margin();
return [
`<div class="code" style="${style}">`,
`<pre class="code_text">${text}</pre>`,
'</div>',
`<div class="codeMarginBottom" style="${marginStyle}"></div>`,
].join('');
},
heading(options) {
const { depth, tokens } = options;
const parsedContent = this.parser.parseInline(tokens);
const headingStyle = skuConfig?.heading?.h(depth);
const hNumStyle = skuConfig?.heading?.hNum(depth);
const marginStyle = skuConfig?.heading?.margin(depth);
return [
`<div class="heading${depth}" style="${headingStyle}">`,
`<span style="${hNumStyle}">•</span>`,
`${parsedContent}</div>`,
`<div class="headingMarginBottom" style="${marginStyle}"></div>`,
].join('');
},
hr() {
const marginBottom = skuConfig?.margin();
const marginTop = skuConfig?.paragraphMargin();
const style = skuConfig?.hr();
return [
`<div class="hrMarginTop" style="${marginTop}"></div>`,
`<div class="hr" style="${style}"></div>`,
`<div class="hrMarginBottom" style="${marginBottom}"></div>`,
].join('');
},
blockquote(options) {
const parsedContent = this.parser.parse(options.tokens);
const style = skuConfig?.blockquote();
const marginStyle = skuConfig?.margin();
return [
`<div class="blockquote" style="${style}">${parsedContent}</div>`,
`<div class="blockquoteMarginBottom" style="${marginStyle}"></div>`,
].join('');
},
list(options) {
listDepth++;
// 为有序列表计算起始序号,默认为1
const startNumber = options.ordered ? (options.start || 1) : null;
// 处理列表项,为有序列表项添加序号
const itemsHtml = options.items.map((item, index) => {
const parsedContent = this.parser.parse(item.tokens);
// 计算当前列表项的序号
const itemNumber = options.ordered ? (startNumber + index) : null;
return this.listitem({
...item,
text: parsedContent,
ordered: options.ordered,
number: itemNumber // 传递序号到列表项
});
}).join('');
// 根据列表类型和深度应用样式
const listTypeClass = options.ordered ? 'ol' : 'ul';
const style = skuConfig?.list(listDepth);
const marginStyle = skuConfig?.margin();
const result = [
`<div style="${style}" class="${listTypeClass}${listDepth - 1}">${itemsHtml}</div>`,
// `<div class="listMarginBottom" style="${marginStyle}"></div>`,
].join('');
listDepth--;
return result;
},
listitem(options) {
const liNumStyle = skuConfig?.listitem?.liNum();
const olNumStyle = skuConfig?.listitem?.olNum();
// 有序列表项添加序号前缀
const numberPrefix = options.ordered && options.number
? `<span class="olNum" style="${olNumStyle}">${options.number}.</span>`
: `<span class="liNum" style="${liNumStyle}">・</span>`;
return `<div class="li">${numberPrefix}${options.text}</div>`;
},
table(options) {
const headerCells = options.header.map((cell, index) => {
const align = options.align[index] || '';
return this.tablecell({
cell,
isHeader: true,
align
});
}).join('');
const headerRow = this.tablerow({
cells: headerCells,
isHeader: true
});
const bodyRows = options.rows.map((row, rowIndex) => {
const cells = row.map((cell, cellIndex) => {
const align = options.align[cellIndex] || '';
return this.tablecell({
cell,
isHeader: false,
align
});
}).join('');
return this.tablerow({
cells,
isHeader: false,
rowIndex
});
}).join('');
const style = skuConfig?.table?.table();
const marginStyle = skuConfig?.margin();
return [
`<div class="table" style="${style}" data-type="${options.type}">`,
`<div class="tableHeader">${headerRow}</div>`,
`<div class="tableBody">${bodyRows}</div>`,
'</div>',
`<div class="tableMarginBottom" style="${marginStyle}"></div>`,
].join('');
},
// 表格行渲染
tablerow(options) {
// options包含:cells(单元格HTML)、isHeader(是否表头行)、rowIndex(行索引)
const rowType = options.isHeader ? 'headerRow' : 'bodyRow';
return `<div class="tableRow ${rowType}" data-index="${options.rowIndex || 0}">${options.cells}</div>`;
},
tablecell(options) {
// options包含:cell(单元格数据)、isHeader(是否表头)、align(对齐方式)
const content = this.parser.parseInline(options.cell.tokens);
const cellType = options.isHeader ? 'headerCell' : 'bodyCell';
const alignClass = options.align ? `align${options.align}` : '';
const tableCellStyle = skuConfig?.table?.tableCell();
const headerCellStyle = skuConfig?.table?.headerCell();
const bodyCellStyle = skuConfig?.table?.bodyCell();
if (options.isHeader) {
return `<span style="${tableCellStyle};${headerCellStyle}" class="tableCell ${cellType} ${alignClass}">${content}</span>`;
} else {
return `<span style="${tableCellStyle};${bodyCellStyle}" class="tableCell ${cellType} ${alignClass}">${content}</span>`;
}
},
paragraph(options) {
const parsedContent = this.parser.parseInline(options.tokens);
const style = skuConfig?.paragraph();
const marginStyle = skuConfig?.paragraphMargin();
return [
`<span class="paragraph" style="${style}">${parsedContent}</span>`,
`<div style="${marginStyle}" class="paragraphMargin"></div>`
].join('');
},
// inline markdown
strong(options) { // 加粗
const { tokens } = options;
const style = skuConfig?.strong();
const parsedContent = this.parser.parseInline(tokens);
return `<span class="strong" style="${style}">${parsedContent}</span>`;
},
em(options) { // 斜体
const { tokens } = options;
const style = skuConfig?.em();
const parsedContent = this.parser.parseInline(tokens);
return `<span class="em" style="${style}">${parsedContent}</span>`;
},
codespan(options) {
const { text } = options;
const style = skuConfig?.codespan();
return `<span class="codespan" style="${style}">${text}</span>`;
},
br() {
const style = skuConfig?.br();
return `<div style="${style}"></div>`;
},
};
marked.use(options);
marked.use({ renderer });
const renderMarkdown = (markdownStr) => {
const latexStyle = skuConfig.latex();
markdownStr = markdownStr.replace(/(<latex\s+style=)("[^"]*")/g, `$1"${latexStyle}"`);
console.error('renderMarkdown markdownStr=', markdownStr);
const markdownStrParsed = marked.parse(markdownStr, options);
console.error('renderMarkdown markdownStrParsed=', markdownStrParsed);
return markdownStrParsed;
}
export {
renderMarkdown,
};