专注小程序 / APP 开发,用代码改变生活

获取方案
全国分站 主站首页 北京分站 石家庄分站 唐山分站 保定分站 廊坊分站 沧州分站 郑州分站 邯郸分站

小程序里做PPT:我的踩坑实录

APP开发 2026-10-26 0 阅读 0 点赞 原创

去年接了个私活,客户要在自己的小程序里加一个「生成方案PPT」的功能。需求听起来不复杂:用户在手机上填几个表单,点一下,导出一份能发到微信里的PPT。我一开始以为找个库调一下就行,结果前后折腾了将近三周。这篇文章把过程和一些关键决策记下来,给后面遇到类似需求的朋友省点时间。

先说结论:小程序里没有「原生PPT」这回事

很多人第一反应是搜「小程序 PPT 库」,然后发现搜出来的东西要么是 H5 的,要么是 Node 端的。原因很简单:PPT 的本质是一个 zip 包,里面装着 XML 和资源文件(OOXML 规范)。而小程序运行环境里没有 Node 的 fs、zlib、Buffer,也没有浏览器里的 Blob 下载能力,所以那些基于 pptxgenjs 的方案在小程序里基本跑不通。

我当时试过直接引入 pptxgenjs,编译能过,运行直接报错,卡在 Buffer is not defined。后来用 buffer 的 polyfill 补上,又卡在 zip 生成阶段,因为 jszip 依赖的流式 API 在小程序里也不完整。

如果你的需求只是「展示」,不是「导出可编辑的 PPT 文件」,那完全没必要走 OOXML 这条路,用 Canvas 画图 + 图片导出就够了。

三条可行路线,按成本从低到高

路线一:Canvas 画图,导出图片或 PDF

这是最省事的方案。用 canvas 2d 把每一页内容画出来,然后 wx.canvasToTempFilePath 导出图片,再拼成 PDF 或者直接发图片。

优点是纯前端、无依赖、可控性强;缺点也很明显:导出的东西不能编辑,客户如果拿去改字,就得重做。适合「汇报截图」「宣传长图」这类场景。

const query = wx.createSelectorQuery()
query.select('#pptCanvas')
  .fields({ node: true, size: true })
  .exec(async (res) => {
    const canvas = res[0].node
    const ctx = canvas.getContext('2d')
    const dpr = wx.getSystemInfoSync().pixelRatio
    canvas.width = 750 * dpr
    canvas.height = 1334 * dpr
    ctx.scale(dpr, dpr)
    // 逐页绘制,每页导出一次
    drawPage(ctx, pages[currentPage])
    const temp = await wx.canvasToTempFilePath({
      canvas,
      fileType: 'png'
    })
    // temp.tempFilePath 拿去上传或保存
  })

路线二:服务端生成,小程序只负责传参和下载

这是我现在最推荐的方案。小程序端把用户填的数据 POST 给后端,后端用 pptxgenjs 或 Python 的 python-pptx 生成文件,返回一个临时下载链接,小程序用 wx.downloadFile 拉下来,再 wx.openDocument 打开或 wx.saveFile 保存。

wx.downloadFile({
  url: 'https://api.example.com/ppt/xxx.pptx',
  success(res) {
    if (res.statusCode === 200) {
      wx.openDocument({
        filePath: res.tempFilePath,
        fileType: 'pptx',
        showMenu: true
      })
    }
  }
})

注意两个坑:一是 openDocument 的 showMenu: true 一定要开,不然用户没法转发;二是下载域名必须在小程序后台配好,临时链接最好带过期时间,避免被刷。

路线三:前端拼 OOXML,自己打 zip

如果业务上坚决不能有后端,那就得自己实现。核心是两件事:把每页内容转成 slideN.xml,再用一个能在小程序里跑的 zip 库打包。

zip 这块我最后用的是 fflate,它对小程序环境比较友好,不依赖 Node 的流。生成一个最小可用的 pptx,至少需要这些文件:

  • [Content_Types].xml:声明各类文件的 MIME
  • _rels/.rels:包级关系
  • ppt/presentation.xml:幻灯片列表
  • ppt/slides/slide1.xml:每页内容
  • ppt/slides/_rels/slide1.xml.rels:每页的关系文件

文字用 <a:t> 标签包,位置用 <a:off> 和 <a:ext> 控制。这套东西写起来不难,但特别琐碎,一个命名空间写错,PowerPoint 直接提示文件损坏。我建议先用桌面版 PowerPoint 手动做一个两页的 pptx,解压出来当模板,然后只替换文本节点,比从零写靠谱得多。

几个实际踩过的坑

  • 字体问题:小程序里能用的字体有限,PPT 里写死「微软雅黑」在手机上预览会回退成默认字体。建议在 XML 里显式指定 latin 和 ea 字体,或者干脆用系统默认。
  • 图片体积:Canvas 导出的 PNG 动辄几百 KB,塞进 pptx 后文件轻松超过 10MB,微信转发会失败。导出时用 wx.compressImage 压一下,或者改用 JPEG。
  • 文件名中文:wx.saveFile 对中文文件名支持不稳定,建议用时间戳命名,展示层再处理。
  • 真机差异:开发者工具里 Canvas 尺寸正常,真机上因为 DPR 不同经常错位,务必用 pixelRatio 做缩放。

我的选择

最后这个项目我走了路线二。原因很实际:客户后续还要在 PC 端编辑这些 PPT,图片方案满足不了;而纯前端拼 XML 的维护成本,对一个只有我一个人的项目来说太高了。后端用 pptxgenjs 写了个接口,模板固定、内容动态,一天就调通了。

如果你也在做类似的功能,先问清楚一件事:导出的文件需不需要被二次编辑。这个问题的答案,基本就决定了你该走哪条路。

小程序定制开发到底是什么意思小程序模版:别急着套,先看这三点

评论 (0)

还没有评论,快来抢沙发吧~

好想法,值得被认真交付

从小程序、APP 到全栈网站,一站式把想法变成可落地的产品

微信咨询

微信扫码,直接沟通需求