marked入门教程

一、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: [], // 自定义扩展(后续详细讲解)
});

关键配置说明

  1. gfm: true:开启后支持 GFM 特有语法:

    • 表格(如上文中的表格示例)
    • 删除线(~~文本~~ 转为 <del>文本</del>
    • 任务列表(- [x] 已完成- [ ] 未完成
    • 自动链接(直接写 https://xxx 会自动转为 <a> 标签)
  2. breaks: true :开启后,Markdown 中的单个 \n 会被转为 <br>,适合解析换行频繁的内容(如评论区)。

  3. headerIds: true :开启后,标题会自动生成 id,方便锚点跳转:

    • Markdown:# 一级标题
    • HTML:<h1 id="一级标题">一级标题</h1>
    • 可通过 headerPrefix 添加前缀:headerPrefix: 'md-'<h1 id="md-一级标题">一级标题</h1>

四、高级功能:自定义渲染器

markedRenderer 类允许你自定义每一种 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.jsprism.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>

九、常见问题与解决方案

  1. 问题 :中文标题生成的 id 包含中文,锚点跳转失效?
    解决方案 :使用 slugger 自定义 id 生成规则,将中文转为拼音或哈希值(可配合 slugify 库)。

  2. 问题 :解析大段 Markdown 内容时性能卡顿?
    解决方案

    • 采用分片解析或异步解析
    • 避免实时预览时频繁触发解析(添加防抖处理)
    • 服务端预解析 Markdown 为 HTML,前端直接渲染
  3. 问题 :不支持 Mermaid 流程图、数学公式?
    解决方案

    • Mermaid:扩展 marked 语法,配合 mermaid 库渲染
    • 数学公式:使用 katexmathjax,扩展 marked 解析 $公式$ 语法

总结

  1. marked 是轻量高速的 Markdown 解析库,核心 API 为 marked.parse(),支持浏览器/Node.js 双环境。
  2. 核心配置可控制 GFM 兼容、换行处理、标题 ID 等,自定义 Renderer 可修改元素渲染逻辑。
  3. 代码高亮需配合 highlight.js,XSS 防护优先使用 dompurify,扩展语法通过 extensions 实现。
  4. 适用场景:服务端批量解析、前端简单预览、轻量 Markdown 功能集成,不适合复杂富文本编辑。
相关推荐
GDAL9 小时前
js的markdown js库对比分析
javascript·markdown
secondyoung2 天前
Pandoc转换Word文档:使用Lua过滤器统一调整Pandoc文档中的图片和表格格式
经验分享·junit·word·lua·markdown·pandoc·mermaid
伟贤AI之路4 天前
原创分享:Markdown转思维导图,一键导出SVG、PNG、JPG、PDF
markdown
yuhaiqun19898 天前
Typora 技能进阶:从会写 Markdown 到玩转配置 + 插件高效学习笔记
经验分享·笔记·python·学习·学习方法·ai编程·markdown
臼犀8 天前
孩子,那不是说明书,那是祈祷文
人工智能·程序员·markdown
用户298698530148 天前
如何在 C# .NET 中将 Markdown 转换为 PDF 和 Excel:完整指南
后端·c#·markdown
星夜落月8 天前
从零开始:在服务器上部署Material for MkDocs完全指南
运维·markdown·建站
草帽lufei9 天前
VSCode+PicGo实现Markdown图床自动同步
markdown·visual studio code
十五年专注C++开发9 天前
Typora:优雅的 Markdown 编辑器
编辑器·markdown