🎉 未来新方向!轻松生成分享海报的神器 —— 零HTML!
在日常开发中,生成分享海报几乎是所有 B 端 / C 端项目的刚需。
不论是商品推广、活动宣传,还是问诊报告、小程序分享,海报生成总是绕不过的一道坎。
手写 canvas?布局复杂 + 尺寸计算让人头疼;
用 html2canvas?不支持跨域图片 + 不同端兼容性差;
用 node-canvas 服务端生成?部署难、成本高、不易调试。
于是,我们造了个轮子——
🌟 gen-poster-f:一套极易扩展的前端海报生成框架,基于 canvas 实现,你只关注布局,canvas让它来。拥有强大的布局能力与灵活的组件机制!
💡 为什么我们需要 gen-poster-f?
开发中,我们遇到这些真实问题:
- ❌ 使用 canvas 手写布局,非常麻烦,代码难维护;
- ❌ 图片多、文字多,绘制逻辑很快变成「屎山」;
- ❌ 想动态生成活动海报,还要处理异步加载、字体兼容、分辨率适配……
- ❌ 一旦需求变化,整张海报都要改,复用性低;
- ❌ 小程序 / H5 想复用海报逻辑?做不到!
于是我们参考 Flutter 的布局思想,设计了一套基于 Widget 渲染的 canvas 框架。写 canvas,就像在写 Flutter 一样!
🧩 特性一览
✨ 声明式组件化布局
通过 Widget 树的方式描述海报内容,完全告别手写 ctx.fillRect() 的混乱逻辑。
Container({
width: 300,
height: 300,
color: Colors.grey200,
alignment: Alignment.center,
child: Container({
width: 100,
height: 100,
color: Colors.blue
})
});
✨ 强大的布局系统
- 支持容器嵌套(Row / Column / Stack / Positioned 等)
- 支持图片、文字、二维码、圆角、边框、背景、阴影等样式
- 自动布局、对齐、缩放适配,多分辨率下效果一致
✨ 轻松导出高清海报
原生 toDataURL()、toCanvas() 等导出方式,满足各种平台分享需求。
✨ 开箱即用的组件库
已内置常用组件:
✅ Text、Image、SizedBox、Container、Row、Column、Positioned ……
也可自定义组件,自由组合,打造专属海报模板!
✨ 灵活扩展 & 二次封装
- 支持纯 html 网页引入
- 支持写成 Vue / React 组件
- 纯 Js/ Ts 编码,零 HTML
- 支持在小程序中使用(抖音 / 微信 / uniapp 等平台)
- 支持服务端渲染 NodeCanvas(计划中)
🚀 快速开始
- 1安装
npm install gen-poster-f
- 2初始化
const canvas = document.querySelector("canvas");
const dpr = canvasConfigData.dpr;
const scale = canvasConfigData.scale || 1;
const width =canvasConfigData.width;
const height = canvasConfigData.height;
const ctx = canvas.getContext("2d");
canvas.width = width * dpr * scale;
canvas.height = height * dpr * scale;
ctx.scale(1 / dpr, 1 / dpr)
GenPlatformConfig.InitInstance({
screenWidth: canvas.width,
screenHeight: canvas.height,
devicePixelRatio: dpr,
strategies: new DefaultNativeStrategies(),
canvas,
renderContext: ctx,
});
- 3运行
runApp(
Container({
width: canvas.width,
height: canvas.height,
color:Colors.black,
child: Stack({
children: generateTrigramWidgets({ radius: 100 }),
}),
})
);
function generateTrigramWidgets({ radius }: { radius: number }): Widget[] {
const trigrams = [
[1, 1, 1], // 乾
[1, 1, 0], // 兑
[1, 0, 1], // 离
[1, 0, 0], // 震
[0, 1, 1], // 巽
[0, 1, 0], // 坎
[0, 0, 1], // 艮
[0, 0, 0], // 坤
];
return trigrams.map((lines, i) => {
const angle = (i / 8) * 2 * Math.PI;
const x = Math.cos(angle) * radius + 140;
const y = Math.sin(angle) * radius + 140;
return Positioned({
left: x,
top: y,
child: Transform.rotate({
alignment: Alignment.center,
angle: (Math.PI / 180) * (360 / 8) * i + (Math.PI / 180) * 90,
child: new Container({
child: Trigram({ lines }),
}),
}),
});
});
}
function Trigram({ lines }: { lines: number[] }): Widget {
return Column({
spacing: 4,
crossAxisAlignment: CrossAxisAlignment.center,
children: lines.map((line) => {
if (line === 0)
return Row({
spacing: 4,
children: [
Container({
width: 10,
height: 4,
decoration: new BoxDecoration({ backgroundColor: Colors.white }),
}),
Container({
width: 10,
height: 4,
decoration: new BoxDecoration({ backgroundColor: Colors.white }),
}),
],
});
return Container({
width: line === 1 ? 24 : 10,
height: 4,
decoration: new BoxDecoration({ backgroundColor: Colors.white }),
});
}),
});
}
- 4:运行效果
使用方式:查看Demo
海报例子
一个完整的GenPoster海报
最终生成效果图
🧪 对比传统写法
展示与原生 canvas 的差异
| 原生Canvas | GenPoster Widget |
|---|---|
| ctx.fillText 布局无约束,不能换行 | Text 支持父组件约束并换行 |
| ctx.fillRect 布局无约束,布局困难 | Container 支持设置尺寸并嵌套,轻松布局 |
| ctx.clip 裁剪难使用 | RectClip、RRectClip 轻松裁剪 |
| 更多... | 更多的新组件... |
查看完整文档和组件示例 👉 gen-poster-doc
🎯 适用场景
- 活动 / 商品分享图
- 问诊报告 / AI 推理可视化图
- 前端项目生成图片上传后台
- 多语言海报自动布局适配
- 静态复杂UI
💬 最后
一切都是Widget。写 canvas 不再痛苦,我们用未来的新方式优雅生成海报!