九宫格切图需用canvas逐块drawImage裁剪,源坐标sx=junit/sy=iunit(unit=img.width/3),每块需独立canvas导出;高清屏下须按devicePixelRatio缩放canvas宽高并调用ctx.scale()。

用 canvas 实现九宫格切图的核心逻辑
九宫格切图不是 HTML5 原生支持的功能,本质是把一张图按 3×3 网格裁成 9 张小图,靠 canvas 的 drawImage() 分区域绘制实现。关键不在“显示”,而在“精准裁剪坐标”——左上角是 (0, 0),宽高需整除 3,否则会丢像素或拉伸。
常见错误:直接用 CSS Grid 排列原图缩略图,那只是“显示为九宫格”,并非真正切割;或者用 clip-path 裁剪但导出不了独立图片文件。
- 原始图必须是正方形(如 900×900),否则切出来每块比例不一致
- 每块尺寸 =
img.width / 3(必须是整数,建议提前校验) - 用
canvas.getContext('2d')逐块调用drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh)
drawImage() 九宫格参数怎么填
参数顺序容易混淆:sx/sy 是源图起点,sw/sh 是源图裁剪宽高,dx/dy 是目标 canvas 上的绘制起点,dw/dh 是绘制到 canvas 上的尺寸(通常和源裁剪尺寸一致)。
对第 (i, j) 块(i、j 从 0 开始),源坐标就是:sx = j * unit, sy = i * unit,其中 unit = img.width / 3。
立即学习“前端免费学习笔记(深入)”;
示例:切第一块(左上):
ctx.drawImage(img, 0, 0, unit, unit, 0, 0, unit, unit);
第二块(中上):
ctx.drawImage(img, unit, 0, unit, unit, 0, 0, unit, unit);
注意:目标 canvas 尺寸不一定要等于 unit,但若要保存为独立图片,每个 canvas 应设为 width=unit、height=unit,再调用 toDataURL()。
如何批量导出 9 张图片的 base64 或 Blob
不能共用一个 canvas,必须为每块创建独立 canvas 元素,否则后绘制的会覆盖前绘制的。
- 用
document.createElement('canvas')创建 9 个 canvas - 每个 canvas 设置
width和height为unit - 每次只在一个 canvas 上 draw 一块,然后调用
canvas.toDataURL('image/png') - 如需下载文件,用
URL.createObjectURL(new Blob([data], {type: 'image/png'}))配合
性能提示:大图(如 3000×3000)切图时,9 次重绘 + toDataURL 可能阻塞主线程,可考虑用 OffscreenCanvas(仅 Chromium/Edge 支持)或分帧处理(setTimeout 分批)。
移动端或高清屏下切图模糊怎么办
根本原因是 canvas 默认以 CSS 像素渲染,而高清屏(devicePixelRatio > 1)下,1 个 CSS 像素对应多个物理像素。不缩放 canvas 内部绘图坐标,就会模糊。
解决方法:根据 window.devicePixelRatio 缩放 canvas 的 width/height 属性,并用 CSS 控制显示尺寸:
const dpr = window.devicePixelRatio || 1;
canvas.width = unit * dpr;
canvas.height = unit * dpr;
canvas.style.width = unit + 'px';
canvas.style.height = unit + 'px';
ctx.scale(dpr, dpr);
这步漏掉,切出来的图在 iPhone 或 MacBook 上看起来发虚,但导出的 base64 数据本身没问题——问题出在渲染层。
真正容易被忽略的是:切图后若要拼回原图验证,必须确保所有 9 块都统一应用了 dpr 缩放逻辑,否则拼接错位。










