更新记录
1.0.1(2026-04-17) 下载此版本
优化自定义配置文档,增加图片点击预览示例
1.0.0(2026-02-13) 下载此版本
初始版本,基于Marked.js 17.0.2优化兼容,完整TypeScript支持,支持全平台运行
平台兼容性
uni-app(3.7.6)
| Vue2 | Vue3 | Chrome | Safari | app-vue | app-nvue | Android | iOS | 鸿蒙 |
|---|---|---|---|---|---|---|---|---|
| √ | √ | √ | √ | √ | √ | √ | √ | √ |
| 微信小程序 | 支付宝小程序 | 抖音小程序 | 百度小程序 | 快手小程序 | 京东小程序 | 鸿蒙元服务 | QQ小程序 | 飞书小程序 | 小红书小程序 | 快应用-华为 | 快应用-联盟 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| √ | √ | √ | √ | √ | √ | √ | √ | √ | √ | √ | √ |
uni-app x(3.7.6)
| Chrome | Safari | Android | iOS | 鸿蒙 | 微信小程序 |
|---|---|---|---|---|---|
| √ | √ | √ | √ | √ | √ |
其他
| 多语言 | 暗黑模式 | 宽屏模式 |
|---|---|---|
| √ | √ | √ |
dh-marked - Markdown解析器(uniapp专用版)
基于Marked.js 17.0.2,专为uniapp优化,兼容全平台(H5、小程序、App)
✨ 特性
- ✅ 全平台兼容 - 支持H5、微信小程序、支付宝小程序、App(iOS/Android)
- ✅ 完整支持 - 支持GitHub风格Markdown(GFM)
- ✅ 轻量快速 - 42KB (gzipped),速度极快
- ✅ TypeScript - 完整的类型定义支持
- ✅ 可扩展 - 支持自定义渲染器和语法扩展
- ✅ 使用方便 - 可以搭配rich-text或者其他富文本显示组件
🚀 快速开始
基础用法
<template>
<view class="markdown-body">
<rich-text :nodes="html"></rich-text>
</view>
</template>
<script>
import { marked } from '@/uni_modules/dh-marked';
export default {
data() {
return {
markdown: '# Hello World\n\n这是**粗体**,这是*斜体*',
};
},
computed: {
html() {
return marked.parse(this.markdown);
},
},
};
</script>
TypeScript支持
import { marked, type MarkedOptions, type Token } from '@/uni_modules/dh-marked';
// 完整的类型提示
const html: string = marked.parse('# Hello');
// 带配置
const options: MarkedOptions = {
breaks: true,
gfm: true,
};
marked.setOptions(options);
📚 核心API
1. marked.parse() - 解析Markdown为HTML
最常用的方法,将Markdown文本转换为HTML。
const html = marked.parse('# 标题\n\n段落内容');
// 输出: <h1>标题</h1>\n<p>段落内容</p>
// 带选项
const html = marked.parse('文本\n换行', {
breaks: true, // 单个换行转<br>
gfm: true, // GitHub风格Markdown
});
参数:
src: string- Markdown源文本options?: MarkedOptions- 可选配置
返回: string | Promise<string> - HTML字符串
2. marked.parseInline() - 只解析内联元素
只解析加粗、斜体、链接等内联元素,不解析标题、列表等块级元素。
const html = marked.parseInline('**粗体** _斜体_ [链接](url)');
// 输出: <strong>粗体</strong> <em>斜体</em> <a href="url">链接</a>
// 不会解析块级元素
marked.parseInline('# 标题\n\n段落');
// 输出: # 标题\n\n段落 (保持原样)
使用场景: 单行文本、评论预览、标题文字
3. marked.setOptions() - 全局配置
设置全局默认配置,影响后续所有的parse调用。
marked.setOptions({
breaks: true, // 单个换行转<br>(默认false)
gfm: true, // GitHub风格Markdown(默认true)
pedantic: false, // 严格遵循markdown.pl(默认false)
silent: false, // 安静模式,遇错不抛异常(默认false)
});
常用配置项:
| 配置项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
breaks |
boolean |
false |
单个换行是否转<br> |
gfm |
boolean |
true |
GitHub风格Markdown |
pedantic |
boolean |
false |
严格模式 |
silent |
boolean |
false |
安静模式 |
renderer |
Renderer |
null |
自定义渲染器 |
tokenizer |
Tokenizer |
null |
自定义分词器 |
walkTokens |
function |
null |
token遍历钩子 |
4. marked.use() - 扩展和自定义
扩展marked的功能,自定义渲染规则或添加新语法。
自定义渲染
// 自定义标题渲染
marked.use({
renderer: {
heading(token) {
const level = token.depth;
const text = this.parser.parseInline(token.tokens);
return `<h${level} class="my-heading" id="${token.text}">${text}</h${level}>\n`;
},
// 自定义链接渲染(用 this.parser.parseInline 保留嵌套格式)
link(token) {
const text = this.parser.parseInline(token.tokens);
return `<a href="${token.href}" class="external-link" target="_blank">${text}</a>`;
},
// 自定义图片渲染(rich-text 只支持标准 HTML 标签,用 @itemclick 处理点击,见示例2)
image(token) {
return `<img src="${token.href}" alt="${token.text || ''}" style="max-width:100%;border-radius:8px;" />`;
},
},
});
添加自定义语法
// 添加警告框语法:!!! 警告内容
marked.use({
extensions: [
{
name: 'alert',
level: 'block',
tokenizer(src) {
const match = /^!!! (.+)\n/.exec(src);
if (match) {
return {
type: 'alert',
raw: match[0],
text: match[1],
};
}
},
renderer(token) {
// rich-text 只支持标准 HTML 标签,不能用 <view>
return `<div class="alert">${token.text}</div>\n`;
},
},
],
});
// 使用
const html = marked.parse('!!! 这是警告信息');
// 输出: <div class="alert">这是警告信息</div>
5. marked.lexer() - 词法分析
将Markdown文本转换为token数组(语法树)。
const tokens = marked.lexer('# 标题\n\n段落内容');
console.log(tokens);
/*
[
{
type: 'heading',
depth: 1,
text: '标题',
tokens: [...]
},
{
type: 'paragraph',
text: '段落内容',
tokens: [...]
}
]
*/
使用场景: 需要分析或修改Markdown结构
6. marked.parser() - 将tokens渲染为HTML
将token数组渲染为HTML字符串。
const tokens = marked.lexer('# Hello');
const html = marked.parser(tokens);
// 输出: <h1>Hello</h1>
// 可以先修改tokens再渲染
tokens[0].text = '修改后的标题';
const newHtml = marked.parser(tokens);
使用场景: 需要在渲染前修改语法树
7. marked.walkTokens() - 遍历所有token
遍历语法树中的所有token,可用于分析或修改内容。
const tokens = marked.lexer('# 标题\n\n[链接](url)');
marked.walkTokens(tokens, (token) => {
// 修改所有链接
if (token.type === 'link') {
token.href = 'https://new-domain.com' + token.href;
}
// 收集所有标题
if (token.type === 'heading') {
console.log(`H${token.depth}: ${token.text}`);
}
});
const html = marked.parser(tokens);
🎨 实战示例
示例1:Markdown文章渲染器
<template>
<scroll-view class="article-container">
<view class="markdown-body">
<rich-text :nodes="html"></rich-text>
</view>
</scroll-view>
</template>
<script>
import { marked } from '@/uni_modules/dh-marked';
export default {
data() {
return {
markdown: '',
};
},
computed: {
html() {
return marked.parse(this.markdown || '');
},
},
onLoad(options) {
// 配置marked
marked.setOptions({
breaks: true, // 换行转<br>
gfm: true, // GitHub风格
});
// 加载文章
this.loadArticle(options.id);
},
methods: {
loadArticle(id) {
uni.request({
url: '/api/article/' + id,
success: (res) => {
this.markdown = res.data.content;
},
});
},
},
};
</script>
<style>
/* GitHub样式的Markdown */
.markdown-body h1 {
font-size: 32px;
font-weight: bold;
margin: 20px 0;
}
.markdown-body h2 {
font-size: 28px;
font-weight: bold;
margin: 18px 0;
}
.markdown-body p {
line-height: 1.6;
margin: 10px 0;
}
.markdown-body code {
background: #f5f5f5;
padding: 2px 4px;
border-radius: 3px;
}
.markdown-body pre {
background: #f5f5f5;
padding: 10px;
border-radius: 5px;
overflow: auto;
}
</style>
示例2:图片点击预览(rich-text @itemclick)
rich-text 组件通过 @itemclick 事件监听内部元素点击,通过 e.detail.node 判断点击的节点类型。
<template>
<view class="markdown-body">
<!-- 绑定 @itemclick,而不是 @tap -->
<rich-text :nodes="html" @itemclick="onImageItemClick"></rich-text>
</view>
</template>
<script setup lang="ts">
import { computed } from 'vue';
import { marked } from '@/uni_modules/dh-marked';
// 自定义图片渲染器(可选,保持原始 img 标签即可)
marked.use({
renderer: {
image(token) {
return `<img src="${token.href}" alt="${token.text || ''}" style="max-width:100%;" />`;
},
},
});
const markdown = `# 图片示例\n\n`;
const html = computed(() => marked.parse(markdown));
// 处理 rich-text 内部元素点击
function onImageItemClick(e: any) {
const node = e.detail?.node;
if (node?.name === 'img') {
const src = node.attrs?.src as string;
if (src) {
uni.previewImage({
urls: [src],
current: src,
});
}
}
}
</script>
注意:
@itemclick是 rich-text 专用的点击事件,e.detail.node.name为 HTML 标签名(如'img'、'a')e.detail.node.attrs包含该节点的所有属性(如src、href)- 不要在 HTML 字符串中使用
@tap等事件属性,rich-text 不支持内联事件
示例3:生成文章目录
import { marked } from '@/uni_modules/dh-marked';
function generateTOC(markdown) {
const tokens = marked.lexer(markdown);
const toc = [];
marked.walkTokens(tokens, (token) => {
if (token.type === 'heading') {
toc.push({
level: token.depth,
text: token.text,
id: token.text.toLowerCase().replace(/\s+/g, '-'),
});
}
});
return toc;
}
// 使用
const markdown = '# 一级标题\n## 二级标题\n### 三级标题';
const toc = generateTOC(markdown);
/*
[
{ level: 1, text: '一级标题', id: '一级标题' },
{ level: 2, text: '二级标题', id: '二级标题' },
{ level: 3, text: '三级标题', id: '三级标题' }
]
*/
示例4:提取纯文本摘要
import { marked } from '@/uni_modules/dh-marked';
function getPlainText(markdown, maxLength = 100) {
const tokens = marked.lexer(markdown);
let text = '';
marked.walkTokens(tokens, (token) => {
if (token.type === 'text') {
text += token.text + ' ';
}
});
const trimmed = text.trim();
return trimmed.length > maxLength ? trimmed.slice(0, maxLength) + '...' : trimmed;
}
// 使用
const summary = getPlainText('# 标题\n\n这是一段**很长**的内容...');
// 输出: "标题 这是一段很长的内容..."
示例5:代码高亮(使用highlight.js)
import { marked } from '@/uni_modules/dh-marked';
import hljs from 'highlight.js'; // 需要另外引入
marked.use({
renderer: {
code(token) {
const language = token.lang || 'plaintext';
const code = token.text;
// 使用highlight.js高亮
const highlighted = hljs.highlight(code, { language }).value;
return `<pre><code class="language-${language}">${highlighted}</code></pre>\n`;
},
},
});
🔧 高级用法
创建独立实例
import { Marked } from '@/uni_modules/dh-marked';
// 创建独立实例,不影响全局配置
const customMarked = new Marked({
breaks: true,
gfm: false,
});
const html1 = customMarked.parse('文本\n换行'); // 有<br>
const html2 = marked.parse('文本\n换行'); // 无<br>
使用Hooks钩子
import { marked } from '@/uni_modules/dh-marked';
marked.use({
hooks: {
// 预处理Markdown
preprocess(markdown) {
// 替换emoji短代码
return markdown.replace(/:smile:/g, '😊').replace(/:heart:/g, '❤️');
},
// 后处理HTML
postprocess(html) {
// 为所有图片添加懒加载
return html.replace(/<img/g, '<img loading="lazy"');
},
},
});
📖 完整API列表
基础API
| API | 用途 | 常用度 |
|---|---|---|
marked.parse() |
解析Markdown为HTML | ⭐⭐⭐⭐⭐ |
marked.parseInline() |
只解析内联元素 | ⭐⭐⭐ |
marked.setOptions() |
全局配置 | ⭐⭐⭐⭐ |
marked.use() |
扩展/自定义 | ⭐⭐⭐⭐ |
marked.getDefaults() |
获取默认配置 | ⭐⭐ |
高级API
| API | 用途 | 常用度 |
|---|---|---|
marked.lexer() |
词法分析 | ⭐⭐⭐ |
marked.parser() |
tokens转HTML | ⭐⭐⭐ |
marked.walkTokens() |
遍历tokens | ⭐⭐⭐ |
类API
| 类 | 用途 | 常用度 |
|---|---|---|
Marked |
独立实例 | ⭐⭐ |
Renderer |
渲染器类 | ⭐⭐⭐ |
Tokenizer |
分词器类 | ⭐⭐ |
Lexer |
词法分析器类 | ⭐⭐ |
Parser |
解析器类 | ⭐⭐ |
TextRenderer |
纯文本渲染 | ⭐⭐ |
Hooks |
钩子系统 | ⭐⭐⭐ |
⚙️ 配置选项详解
MarkedOptions
interface MarkedOptions {
// 单个换行是否转<br>
breaks?: boolean; // 默认: false
// GitHub风格Markdown
gfm?: boolean; // 默认: true
// 严格模式
pedantic?: boolean; // 默认: false
// 安静模式(错误不抛异常)
silent?: boolean; // 默认: false
// 异步解析
async?: boolean; // 默认: false
// 自定义渲染器
renderer?: Renderer;
// 自定义分词器
tokenizer?: Tokenizer;
// 钩子函数
hooks?: Hooks;
// 扩展语法
extensions?: Extension[];
// token遍历函数
walkTokens?: (token: Token) => void;
}
📄 许可证
MIT License
基于 Marked.js - Copyright (c) 2018+, MarkedJS (MIT License)
🔗 相关链接
💡 常见问题
Q: 如何在rich-text中使用?
A: 直接将解析后的HTML传给rich-text组件:
<rich-text :nodes="marked.parse(markdown)"></rich-text>
Q: 图片如何支持预览?
A: 在 rich-text 上绑定 @itemclick,在回调中判断 e.detail.node.name === 'img' 后调用 uni.previewImage,参考示例2。
Q: 支持代码高亮吗?
A: 需要配合highlight.js使用,参考示例5。
Q: 如何生成目录?
A: 使用marked.walkTokens()遍历heading类型的token,参考示例3。
Q: 性能如何?
A: Marked是最快的Markdown解析器之一,10KB的文档解析时间<5ms。

收藏人数:
下载插件并导入HBuilderX
下载插件ZIP
赞赏(5)
下载 227
赞赏 5
下载 11914051
赞赏 1914
赞赏
京公网安备:11010802035340号