更新记录

1.0.0(2026-02-13) 下载此版本

初始版本,基于Marked.js 17.0.2优化兼容,完整TypeScript支持,支持全平台运行


平台兼容性

uni-app(3.6.17)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
-

uni-app x(3.6.17)

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`;
    },

    // 自定义链接渲染
    link(token) {
      return `<a href="${token.href}" class="external-link" target="_blank">${token.text}</a>`;
    },

    // 自定义图片渲染(uniapp图片预览)
    image(token) {
      return `<image src="${token.href}" mode="widthFix" data-src="${token.href}" @tap="previewImage" />`;
    },
  },
});

添加自定义语法

// 添加警告框语法:!!! 警告内容
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) {
        return `<view class="alert">${token.text}</view>\n`;
      },
    },
  ],
});

// 使用
const html = marked.parse('!!! 这是警告信息');
// 输出: <view class="alert">这是警告信息</view>

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:自定义图片渲染(支持预览)

import { marked } from '@/uni_modules/dh-marked';

// 自定义图片渲染
marked.use({
  renderer: {
    image(token) {
      // 为图片添加点击事件属性
      return `<img src="${token.href}" alt="${token.text}" mode="widthFix" data-preview="${token.href}" class="md-image" />`;
    },
  },
});

export default {
  methods: {
    // 图片预览
    handleTap(e) {
      const src = e.target.dataset.preview;
      if (src) {
        uni.previewImage({
          urls: [src],
          current: src,
        });
      }
    },
  },
};

示例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 + ' ';
    }
  });

  return text.trim().slice(0, maxLength) + '...';
}

// 使用
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: 使用自定义渲染器添加点击事件,参考示例2。

Q: 支持代码高亮吗?

A: 需要配合highlight.js使用,参考示例5。

Q: 如何生成目录?

A: 使用marked.walkTokens()遍历heading类型的token,参考示例3。

Q: 性能如何?

A: Marked是最快的Markdown解析器之一,10KB的文档解析时间<5ms。

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT协议