一、marked 核心介绍
marked 是一款轻量、高速、无依赖的 JavaScript Markdown 解析库,核心功能是将 Markdown 文本转换为 HTML 字符串。它的特点是:
- 解析速度在 JS Markdown 库中名列前茅(比 markdown-it 更快)
- 体积小巧(压缩后约 30KB),支持浏览器/Node.js 双环境
- 兼容 GFM(GitHub Flavored Markdown)语法
- 支持灵活的配置和自定义渲染规则
- 无第三方依赖,集成成本极低
二、环境准备与基础使用
1. 安装方式
(1)Node.js 环境(工程化项目)
bash
# npm
npm install marked --save
# yarn
yarn add marked
# pnpm
pnpm add marked
(2)浏览器环境(直接引入)
html
<!-- CDN 引入(最新版本) -->
<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<!-- 指定版本(推荐,避免兼容性问题) -->
<script src="https://cdn.jsdelivr.net/npm/marked@12.0.2/marked.min.js"></script>
2. 最简使用示例
(1)Node.js 环境(ESM 模块化)
javascript
// 引入 marked
import { marked } from 'marked';
// 待解析的 Markdown 内容
const mdContent = `
# 一级标题
## 二级标题
这是一段普通文本,支持**加粗**、*斜体*、~~删除线~~。
- 无序列表项1
- 无序列表项2
- 嵌套列表项
1. 有序列表项1
2. 有序列表项2
[百度链接](https://www.baidu.com)
\`\`\`javascript
// 代码块示例
const a = 10;
console.log(a);
\`\`\`
| 姓名 | 年龄 | 职业 |
| ---- | ---- | ---- |
| 张三 | 25 | 前端开发 |
| 李四 | 28 | 后端开发 |
`;
// 核心方法:parse(将 Markdown 转为 HTML)
const htmlContent = marked.parse(mdContent);
// 输出结果
console.log(htmlContent);
// 可直接插入到 DOM 中(前端场景)
// document.getElementById('content').innerHTML = htmlContent;
(2)浏览器环境(全局变量)
html
<div id="markdown-content"></div>
<script>
// 待解析的 Markdown 内容
const mdContent = '# 这是浏览器环境的 marked 解析\n\n支持**GFM**语法';
// 全局 marked 对象直接调用 parse 方法
const htmlContent = marked.parse(mdContent);
// 插入到页面
document.getElementById('markdown-content').innerHTML = htmlContent;
</script>
3. 核心API说明
marked 的核心 API 非常简洁,主要常用的有:
marked.parse(markdownString [, options]):核心解析方法,接收 Markdown 字符串和配置项,返回 HTML 字符串。marked.setOptions(options):全局设置配置项,后续所有parse调用都会沿用该配置。
三、核心配置项详解
marked 提供了丰富的配置项,用于控制解析行为和渲染效果,常用配置如下(可传入 parse 方法或 setOptions 全局设置):
javascript
import { marked } from 'marked';
// 全局设置配置
marked.setOptions({
// 1. 基础配置
gfm: true, // 启用 GFM 语法(默认 true),支持表格、删除线、任务列表
breaks: false, // 是否将换行符 \n 转换为 <br> 标签(默认 false,GFM 中只有空行才会分段)
pedantic: false, // 是否严格遵循 Markdown 原始规范(默认 false,关闭后更灵活)
sanitize: false, // 已废弃,使用 sanitizer 替代,是否过滤 HTML 标签(默认 false)
smartypants: false, // 是否将直引号转为弯引号(默认 false,优化排版)
// 2. 渲染配置
renderer: new marked.Renderer(), // 自定义渲染器(后续详细讲解)
highlight: null, // 代码块高亮配置(后续详细讲解)
langPrefix: 'language-', // 代码块 class 前缀(默认 'language-',如 <code class="language-javascript">)
headerIds: true, // 是否为标题自动生成 id(默认 true,如 <h1 id="一级标题">)
headerPrefix: '', // 标题 id 前缀(默认空字符串,可自定义避免 id 冲突)
mangle: true, // 是否混淆链接中的邮件地址(默认 true,防止爬虫抓取)
silent: false, // 是否忽略解析错误(默认 false,错误会打印到控制台)
// 3. 安全配置
sanitizer: null, // HTML 内容过滤函数(替代废弃的 sanitize)
extensions: [], // 自定义扩展(后续详细讲解)
});
关键配置说明
-
gfm: true:开启后支持 GFM 特有语法:- 表格(如上文中的表格示例)
- 删除线(
~~文本~~转为<del>文本</del>) - 任务列表(
- [x] 已完成、- [ ] 未完成) - 自动链接(直接写
https://xxx会自动转为<a>标签)
-
breaks: true:开启后,Markdown 中的单个\n会被转为<br>,适合解析换行频繁的内容(如评论区)。 -
headerIds: true:开启后,标题会自动生成id,方便锚点跳转:- Markdown:
# 一级标题 - HTML:
<h1 id="一级标题">一级标题</h1> - 可通过
headerPrefix添加前缀:headerPrefix: 'md-'→<h1 id="md-一级标题">一级标题</h1>
- Markdown:
四、高级功能:自定义渲染器
marked 的 Renderer 类允许你自定义每一种 Markdown 元素的渲染逻辑,比如修改标题的样式、给链接添加默认属性等。
1. 自定义渲染器基础示例
javascript
import { marked, Renderer } from 'marked';
// 1. 创建自定义 Renderer 实例
const customRenderer = new Renderer();
// 2. 重写标题渲染逻辑(h1-h6)
customRenderer.heading = (text, level, raw, slugger) => {
// text:标题文本(已解析为 HTML)
// level:标题层级(1-6)
// slugger:生成唯一 id 的工具
const headerId = `custom-header-${level}-${slugger.slug(raw)}`;
// 给标题添加自定义 class 和 id
return `<h${level} id="${headerId}" class="custom-heading custom-heading-${level}">${text}</h${level}>`;
};
// 3. 重写链接渲染逻辑
customRenderer.link = (href, title, text) => {
// href:链接地址
// title:链接标题(可选)
// text:链接文本
// 添加 target="_blank"(新窗口打开)和 rel="noopener noreferrer"(安全防护)
const titleAttr = title ? `title="${title}"` : '';
return `<a href="${href}" ${titleAttr} target="_blank" rel="noopener noreferrer" class="custom-link">${text}</a>`;
};
// 4. 重写列表项渲染逻辑
customRenderer.listitem = (text, task, checked) => {
// task:是否为任务列表项
// checked:任务是否已完成
if (task) {
// 自定义任务列表样式
return `<li class="custom-task-item"><input type="checkbox" ${checked ? 'checked' : ''} disabled> ${text}</li>`;
}
// 普通列表项添加自定义 class
return `<li class="custom-list-item">${text}</li>`;
};
// 5. 使用自定义渲染器解析 Markdown
const mdContent = `
# 自定义标题
[百度链接](https://www.baidu.com)
- [x] 已完成任务
- [ ] 未完成任务
`;
const htmlContent = marked.parse(mdContent, {
renderer: customRenderer,
gfm: true // 开启 GFM 以支持任务列表
});
console.log(htmlContent);
2. 可重写的核心渲染方法
| 方法名 | 对应 Markdown 元素 | 说明 |
|---|---|---|
heading |
标题(# / ## / ...) | 渲染 h1-h6 |
paragraph |
段落(普通文本) | 渲染 p 标签 |
strong |
加粗(/*) | 渲染 strong 标签 |
em |
斜体(/_) | 渲染 em 标签 |
del |
删除线(~~) | 渲染 del 标签 |
link |
链接(文本) | 渲染 a 标签 |
image |
图片( ) |
渲染 img 标签 |
list |
列表(有序/无序) | 渲染 ul/ol 标签 |
listitem |
列表项 | 渲染 li 标签 |
code |
行内代码(代码) |
渲染 code 标签 |
codeBlock |
代码块(代码) |
渲染 pre+code 标签 |
table |
表格 | 渲染 table 标签 |
tableCell |
表格单元格 | 渲染 td/th 标签 |
五、代码块高亮实现
marked 本身不提供代码高亮功能,需配合高亮库(如 highlight.js 或 prism.js)实现,下面以常用的 highlight.js 为例:
1. 安装 highlight.js
bash
npm install highlight.js --save
2. 代码高亮配置示例
javascript
import { marked } from 'marked';
import hljs from 'highlight.js';
// 引入 highlight.js 样式(可选多种主题)
import 'highlight.js/styles/github-dark.css';
// 配置 marked 的 highlight 方法
const htmlContent = marked.parse(mdContent, {
gfm: true,
highlight: (code, lang, callback) => {
// code:代码块原始内容
// lang:代码块指定的语言(如 javascript、html)
// callback:异步回调(可选,同步场景可直接返回)
// 1. 判断是否指定了语言
if (lang && hljs.getLanguage(lang)) {
try {
// 2. 使用 highlight.js 高亮代码
return hljs.highlight(code, { language: lang }).value;
} catch (err) {
console.error('代码高亮失败:', err);
}
}
// 3. 未指定语言或高亮失败时,使用自动识别
try {
return hljs.highlightAuto(code).value;
} catch (err) {
console.error('自动高亮失败:', err);
}
// 4. 最终失败时,返回原始代码
return code;
},
langPrefix: 'language-' // 与 highlight.js 兼容的 class 前缀
});
3. 浏览器环境代码高亮
html
<!-- 引入 highlight.js -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/highlight.js/styles/github.css">
<script src="https://cdn.jsdelivr.net/npm/highlight.js/highlight.min.js"></script>
<!-- 引入 marked -->
<script src="https://cdn.jsdelivr.net/npm/marked@12.0.2/marked.min.js"></script>
<div id="content"></div>
<script>
const mdContent = `
\`\`\`javascript
const a = 10;
console.log('Hello marked + highlight.js');
\`\`\`
`;
// 配置高亮
const html = marked.parse(mdContent, {
highlight: (code, lang) => {
if (lang && hljs.getLanguage(lang)) {
return hljs.highlight(code, { language: lang }).value;
}
return hljs.highlightAuto(code).value;
}
});
document.getElementById('content').innerHTML = html;
</script>
六、安全防护:防止 XSS 攻击
Markdown 支持嵌入 HTML 标签(默认配置下),如果解析用户提交的 Markdown 内容(如评论区、论坛),可能存在 XSS 攻击风险(比如用户插入 <script>恶意代码</script>)。
1. 方案一:使用 marked 内置 sanitizer(推荐)
marked 推荐使用 sanitizer 配置项,配合第三方安全库(如 dompurify)过滤危险 HTML:
(1)安装 dompurify
bash
npm install dompurify --save
(2)配置 sanitizer
javascript
import { marked } from 'marked';
import DOMPurify from 'dompurify';
// 解析用户提交的 Markdown(可能包含恶意代码)
const unsafeMdContent = `
# 恶意测试
<script>alert('XSS 攻击')</script>
<img src="x" onerror="alert('图片 XSS')">
这是**正常内容**
`;
// 配置 sanitizer,使用 dompurify 过滤危险 HTML
const safeHtmlContent = marked.parse(unsafeMdContent, {
sanitizer: (html) => {
// dompurify 会过滤掉 script、onerror 等危险内容
return DOMPurify.sanitize(html);
}
});
console.log(safeHtmlContent);
// 输出结果中,script 标签和 img 的 onerror 事件会被过滤
2. 方案二:禁用 HTML 解析
如果不需要支持 Markdown 中的 HTML 标签,可直接禁用,从根源上避免 XSS:
javascript
const htmlContent = marked.parse(unsafeMdContent, {
gfm: true,
// 禁用 HTML 解析(所有 HTML 标签会被转义为文本)
renderer: new marked.Renderer(),
// 等价于:
// sanitize: true // 已废弃,但仍可使用(推荐用 sanitizer)
});
七、自定义扩展:扩展 Markdown 语法
marked 支持通过 extensions 配置项扩展自定义 Markdown 语法,比如添加自定义组件、特殊标签等。
示例:扩展 "提示框" 语法
需求:自定义 :::tip 提示内容 ::: 语法,渲染为带样式的提示框。
javascript
import { marked } from 'marked';
// 1. 定义自定义扩展
const tipExtension = {
name: 'tipBlock', // 扩展名称
level: 'block', // 块级扩展(block)/ 行内扩展(inline)
start: (src) => src.match(/:::tip/)?.index, // 匹配开始位置
tokenizer: (src, tokens) => {
// 正则匹配 ::tip 提示框语法
const match = /^:::tip\s*(.*?)\s*:::/s.exec(src);
if (match) {
return {
type: 'tipBlock', // token 类型
raw: match[0], // 原始内容
text: match[1], // 提示框内容
};
}
},
renderer: (token) => {
// 渲染为自定义 HTML 结构
return `<div class="custom-tip-box">
<div class="tip-title">提示</div>
<div class="tip-content">${marked.parse(token.text)}</div>
</div>`;
}
};
// 2. 使用扩展
const mdContent = `
:::tip
这是自定义提示框,支持**加粗**、*斜体*等 Markdown 语法。
:::
普通文本内容。
`;
const htmlContent = marked.parse(mdContent, {
extensions: [tipExtension] // 配置扩展
});
console.log(htmlContent);
八、实战场景:前端 Markdown 预览组件
基于 marked 实现一个简单的实时预览 Markdown 组件(Vue 示例,React 同理):
vue
<template>
<div class="markdown-preview">
<textarea v-model="mdContent" placeholder="请输入 Markdown 内容" class="md-input"></textarea>
<div class="md-output" v-html="htmlContent"></div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
import { marked } from 'marked';
import hljs from 'highlight.js';
import DOMPurify from 'dompurify';
import 'highlight.js/styles/github.css';
// 1. 响应式数据
const mdContent = ref(`
# Markdown 实时预览
支持**加粗**、*斜体*、~~删除线~~。
\`\`\`javascript
// 代码高亮示例
const a = 10;
console.log(a);
\`\`\`
`);
// 2. 计算属性:实时转换 Markdown 为 HTML
const htmlContent = computed(() => {
return marked.parse(mdContent.value, {
gfm: true,
breaks: true,
highlight: (code, lang) => {
if (lang && hljs.getLanguage(lang)) {
return hljs.highlight(code, { language: lang }).value;
}
return hljs.highlightAuto(code).value;
},
sanitizer: (html) => DOMPurify.sanitize(html)
});
});
</script>
<style scoped>
.markdown-preview {
display: flex;
gap: 20px;
padding: 20px;
}
.md-input {
width: 50%;
height: 500px;
padding: 10px;
border: 1px solid #e0e0e0;
border-radius: 4px;
resize: none;
}
.md-output {
width: 50%;
padding: 10px;
border: 1px solid #e0e0e0;
border-radius: 4px;
overflow: auto;
}
/* 代码高亮样式兼容 */
.md-output pre {
padding: 10px;
background: #f5f5f5;
border-radius: 4px;
overflow: auto;
}
.md-output code {
padding: 2px 4px;
background: #f5f5f5;
border-radius: 2px;
}
</style>
九、常见问题与解决方案
-
问题 :中文标题生成的
id包含中文,锚点跳转失效?
解决方案 :使用slugger自定义id生成规则,将中文转为拼音或哈希值(可配合slugify库)。 -
问题 :解析大段 Markdown 内容时性能卡顿?
解决方案:- 采用分片解析或异步解析
- 避免实时预览时频繁触发解析(添加防抖处理)
- 服务端预解析 Markdown 为 HTML,前端直接渲染
-
问题 :不支持 Mermaid 流程图、数学公式?
解决方案:- Mermaid:扩展
marked语法,配合mermaid库渲染 - 数学公式:使用
katex或mathjax,扩展marked解析$公式$语法
- Mermaid:扩展
总结
marked是轻量高速的 Markdown 解析库,核心 API 为marked.parse(),支持浏览器/Node.js 双环境。- 核心配置可控制 GFM 兼容、换行处理、标题 ID 等,自定义
Renderer可修改元素渲染逻辑。 - 代码高亮需配合
highlight.js,XSS 防护优先使用dompurify,扩展语法通过extensions实现。 - 适用场景:服务端批量解析、前端简单预览、轻量 Markdown 功能集成,不适合复杂富文本编辑。
)