npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

towxml-canvas-renderer

v1.0.3

Published

微信小程序 Markdown 渲染器,将 Markdown 内容渲染到 Canvas

Readme

Markdown 渲染器架构说明

概述

本模块使用策略模式 + 工厂模式 + 模板方法模式重构,将原本的单体文件(985行)拆分为多个职责明确的小文件,提高了代码的可维护性和可扩展性。

重要说明:本项目基于 towxml 包,接收 towxml() 方法解析 Markdown 后返回的节点树数据(TowxmlNode),并将其渲染到 Canvas 上。使用前需要先使用 towxml 将 Markdown 文本解析为节点树。

关于 towxml 的使用方法,请参考官方文档:towxml 3.0 如何使用

目录结构

markdown-renderer/
├── index.ts                    # 主入口,导出 MarkdownRenderer 和类型
├── types.ts                    # 类型定义(TowxmlNode, RenderStyles, Layout, RenderResult, RenderContext)
├── config.ts                   # 默认样式配置
├── MarkdownRenderer.ts         # 主渲染器类(协调各个渲染器)
├── renderers/                  # 渲染器目录
│   ├── index.ts                # 渲染器工厂(RenderFactory)
│   ├── base/
│   │   └── BaseRenderer.ts     # 基础渲染器抽象类(模板方法模式)
│   ├── text/
│   │   └── TextRenderer.ts     # 文本渲染器
│   ├── heading/
│   │   └── HeadingRenderer.ts  # 标题渲染器(h1-h6)
│   ├── paragraph/
│   │   └── ParagraphRenderer.ts # 段落渲染器
│   ├── code/
│   │   └── CodeRenderer.ts     # 代码块渲染器(行内/块级)
│   ├── strong/
│   │   └── StrongRenderer.ts   # 粗体渲染器(支持粗体行内代码)
│   ├── emphasis/
│   │   └── EmphasisRenderer.ts # 斜体渲染器
│   ├── blockquote/
│   │   └── BlockquoteRenderer.ts # 引用块渲染器
│   ├── list/
│   │   └── ListRenderer.ts     # 列表渲染器(ul/ol/li)
│   ├── table/
│   │   └── TableRenderer.ts    # 表格渲染器
│   └── hr/
│       └── HrRenderer.ts       # 分割线渲染器
├── utils/                      # 工具类目录
│   ├── TextUtils.ts           # 文本处理工具(换行、计算高度、提取文本)
│   ├── CanvasUtils.ts         # Canvas 绘制工具(圆角矩形等)
│   └── StateManager.ts        # 状态管理(保存/恢复 Canvas 状态)
└── helpers/                   # 辅助类目录
    └── NodeMatcher.ts         # 节点匹配逻辑(判断节点类型)

设计模式说明

1. 策略模式(Strategy Pattern)

  • 每个节点类型对应一个独立的渲染器策略类
  • 所有渲染器继承自 BaseRenderer
  • 通过 canHandle() 方法判断是否可以处理该节点

2. 工厂模式(Factory Pattern)

  • RenderFactory 负责创建和管理所有渲染器实例
  • 根据节点类型自动选择合适的渲染器
  • 支持特殊规则优先匹配(如 view 标签的 class 判断)

3. 模板方法模式(Template Method Pattern)

  • BaseRenderer 定义渲染流程骨架:
    1. 保存状态 (saveState)
    2. 执行具体渲染 (renderInternal - 子类实现)
    3. 恢复状态 (restoreState)

4. 依赖注入

  • RenderContext 包含所有渲染器需要的共享状态和工具方法
  • 避免在各个渲染器中重复初始化

使用方式

前置准备

在使用本渲染器之前,需要先使用 towxml 将 Markdown 文本解析为节点树。

在微信小程序中使用 towxml

根据 towxml 官方文档,需要在 app.js 中引入 towxml:

// app.js
App({
  // 引入 towxml 3.0 解析方法
  towxml: require('/towxml/index')
})

然后在页面中使用:

// pages/index/index.js
const app = getApp()

// 使用 towxml 解析 Markdown
const articleData = app.towxml('# Hello World\n\n这是一段 Markdown 内容', 'markdown', {
  base: 'https://xxx.com',        // 相对资源的 base 路径(可选)
  theme: 'light',                  // 主题:'light' 或 'dark'(可选,默认 'light')
  events: {                        // 绑定事件(可选)
    tap: (e) => {
      console.log('tap', e)
    }
  }
})

towxml API 说明

app.towxml(str, type, options) 参数:

  • str [必选] - HTML 或 Markdown 字符串
  • type [必选] - 需要解析的内容类型:'html''markdown'
  • options [可选] - 配置选项对象
    • base [string] - 用于指定静态相对资源的 base 路径,例如:'https://xx.com/static/'
    • theme [string] - 主题设置,默认:'light',可选:'light''dark' 或其它自定义主题
    • events [object] - 用于为元素绑定事件,key 为事件名称,value 必须为一个函数

基本使用

import { MarkdownRenderer } from 'towxml-canvas-renderer'
const app = getApp()

// 1. 使用 towxml 解析 Markdown
const markdownText = '# 标题\n\n这是一段内容'
const articleData = app.towxml(markdownText, 'markdown')

// 2. 创建渲染器并渲染
const ctx = canvas.getContext('2d')
const renderer = new MarkdownRenderer(ctx, canvasWidth, canvasHeight, {
  // 可选的自定义样式
})
const result = renderer.render(articleData)

扩展新节点类型

  1. renderers/ 下创建新的渲染器目录
  2. 实现继承自 BaseRenderer 的渲染器类
  3. RenderFactory 中注册新渲染器

示例:

export class CustomRenderer extends BaseRenderer {
  canHandle(node: TowxmlNode): boolean {
    return node.tag === 'custom'
  }
  
  protected renderInternal(node: TowxmlNode, layout: Layout): Layout {
    // 实现渲染逻辑
    return layout
  }
}

优势

  1. 职责分离:每个渲染器只负责一种节点类型
  2. 易于扩展:新增节点类型只需新增一个渲染器类
  3. 易于测试:可以单独测试每个渲染器
  4. 易于维护:修改某种节点的渲染逻辑不会影响其他节点
  5. 代码复用:工具类可在多个渲染器中复用

在微信小程序中使用

安装

npm install towxml-canvas-renderer
# 或使用 pnpm
pnpm add towxml-canvas-renderer

构建 npm

  1. 打开微信开发者工具
  2. 点击菜单栏:工具 -> 构建 npm
  3. 构建完成后,node_modules 目录下会生成 miniprogram_npm 目录

引入使用

完整示例:

// pages/index/index.js
import { MarkdownRenderer, defaultStyles } from 'towxml-canvas-renderer'
const app = getApp()

Page({
  data: {
    canvasWidth: 750,
    canvasHeight: 1000
  },
  
  onReady() {
    // 1. 使用 towxml 解析 Markdown 文本
    const markdownText = `# 标题\n\n这是一段 **Markdown** 内容`
    const articleData = app.towxml(markdownText, 'markdown', {
      base: 'https://your-domain.com',  // 可选:静态资源 base 路径
      theme: 'light'                    // 可选:主题设置
    })

    // 2. 获取 Canvas 上下文
    const query = wx.createSelectorQuery()
    query.select('#canvas')
      .fields({ node: true, size: true })
      .exec((res) => {
        const canvas = res[0].node
        const ctx = canvas.getContext('2d')
        
        // 设置 Canvas 尺寸
        const dpr = wx.getSystemInfoSync().pixelRatio
        canvas.width = this.data.canvasWidth * dpr
        canvas.height = this.data.canvasHeight * dpr
        ctx.scale(dpr, dpr)

        // 3. 创建渲染器实例
        const renderer = new MarkdownRenderer(
          ctx, 
          this.data.canvasWidth, 
          this.data.canvasHeight, 
          {
            // 可选:自定义样式配置
            padding: 40,
            baseFontSize: 28,
            colors: {
              text: '#333333',
              // ... 其他样式配置
            }
          }
        )

        // 4. 渲染 Markdown 内容(articleData 是 towxml 解析后的节点树)
        const result = renderer.render(articleData)
        
        if (result.success) {
          console.log('渲染成功,高度:', result.height)
        } else {
          console.error('渲染失败:', result.error)
        }
      })
  }
})

重要提示

  • articleData 必须是 app.towxml() 方法返回的节点树数据(TowxmlNode 类型),不能直接传入 Markdown 文本字符串
  • 关于 towxml 的详细使用方法,请参考 towxml 3.0 使用文档

自定义样式

import { MarkdownRenderer, defaultStyles } from 'towxml-canvas-renderer'

const renderer = new MarkdownRenderer(ctx, width, height, {
  ...defaultStyles,
  padding: 20,
  baseFontSize: 32,
  colors: {
    ...defaultStyles.colors,
    text: '#000000',
    h1: '#1a1a1a',
  }
})

相关文档

体验小程序

项目提供了一个体验版微信小程序,扫码即可在真实环境下验证 Markdown 渲染效果。

体验小程序二维码