JSON转Sketch插件实战:用json-sketchapp自动生成设计稿
简介json-sketchapp 是一款面向设计师与前端开发者的 Sketch 插件用于将 JSON 数据文件一键转换为 Sketch 设计稿适合需要从数据驱动批量生成界面、搭建设计规范或探索自动化设计流程的团队。插件基于 skpm 构建并借助 SketchJavaScript 扩展能力同时关联 yoga 布局相关特性具备较高的可定制性。资源包共 9 个文件核心包含 4 个 JSON 文件用于示例数据和包配置、JavaScript 源码、Markdown 说明文档、项目配置文件及插件图标整体压缩包仅 81KB结构紧凑便于快速上手与二次开发。通过源码与示例读者可以学习插件的构建与监听模式、自定义 Babel 配置方法以及 npm 打包流程也可直接安装体验从 JSON 导入 Sketch 的操作路径。已有 671 人学习浏览适合希望扩展 Sketch 工作流、研究插件开发或实现设计数据化的中高级用户。1. json-sketchapp 是干什么的一个把 JSON 变成 Sketch 文件的插件第一次看到 json-sketchapp 这个名字我以为是又一个 JSON 转网页预览的小工具。真正在 Sketch 里跑过一次才明白它做的是把 JSON 文件直接转换成 Sketch 文件你给一份结构化的 JSON它就能生成对应的图层、文本、矩形甚至画板。数据长什么样输出的图层树就长什么样。如果你经常处理“前端给 JSON、设计要出稿”这种交接这个插件就是从数据到设计文件的快速通道。它适合想省重复布局时间的 UI 设计师也适合需要把接口结构快速落成草稿的工程师想研究 Sketch 插件怎么做的人也能从 skpm、Yoga、SketchJavaScript 这套组合里学到东西。2. 插件机制skpm、SketchJavaScript 与 Yoga 布局的关系普通的 Sketch 插件大多是把选中图层改改坐标、改改颜色json-sketchapp 不是这种。它要把一份结构化的 JSON 变成一棵图层树背后至少有三块能力skpm 负责工程化SketchJavaScript 负责调用 Sketch 原生 APIYoga 负责算布局。下面按这个顺序拆。2.1 为什么这类插件都会用 skpm 做工程化早先写 Sketch 插件用 CocoaScript调试要对着 Sketch 日志窗口猜打包也是手工复制文件。skpm 出现之后插件工程变成了标准 npm 项目用 import/export 写源码跑一次构建就能产出.sketchplugin。json-sketchapp 选 skpm不只是因为它流行而是因为 SketchJavaScript 这套 API 需要模块化打包源码里要引用sketch/dom、yoga-layout这类 npm 包没有 skpm 会很难受。# 在工程根目录安装 skpm 相关依赖 npm install # 监听源码变化自动重新打包 npm run dev # 构建一份可发布的插件包 npm run buildnpm install会把 skpm、yoga-layout、sketch 相关模块全部装进 node_modulesnpm run dev进入监听模式适合边改源码边在 Sketch 里跑npm run build生成最终插件包。注意 dev 模式只负责打包不负责在 Sketch 里重新加载插件。我一般改完代码会去插件菜单重新触发一次或者在开发环境里用 skpm 的刷新能力否则很容易出现“改了没反应”的错觉。2.2 Yoga 在 json-sketchapp 里扮演什么角色Yoga 是一套跨平台布局引擎实现了 flexbox 的核心规则。为什么一定需要它因为 JSON 转 Sketch 不是把字段一对一套上去就完了真实 UI 是嵌套的子节点怎么排、间距多少、宽度怎么分配需要一个稳定的计算答案。Yoga 接受一棵节点树每个节点带 width、height、margin、padding、flexDirection 等样式最后由它算出每个节点的最终 frame插件再用这个 frame 去创建 Sketch 图层。这个设计带来的直接好处是JSON 里的子节点不需要手写 x 和 y。你在父节点上声明布局方向Yoga 会负责把子节点排开。比如一个横向排列的按钮组只要在容器上写flexDirection: row子节点就会从左到右依次排想换行就写flexWrap: wrap。这套写法和前端 flex 布局几乎一样所以从前端切过来的开发者几乎不用额外学。2.3 一段最短实现JSON 节点怎么变成 Sketch 图层源码层面一次转换可以拆成三步读 JSON 建节点树喂给 Yoga 计算布局再用计算结果创建 Sketch 图层。下面是一段更接近真实实现的流程示意import Yoga from yoga-layout function buildYogaTree(yogaParent, jsonChildren) { jsonChildren.forEach((childJson) { const childYoga Yoga.Node.create() // 宽高是布局计算的基本输入单位建议统一用 pt childYoga.setWidth(childJson.width || 0) childYoga.setHeight(childJson.height || 0) if (childJson.style childJson.style.margin) { childYoga.setMargin(Yoga.Edge.All, childJson.style.margin) } yogaParent.appendChild(childYoga) if (childJson.children) { buildYogaTree(childYoga, childJson.children) } }) } function convert(context) { const json JSON.parse(context.actionContext) const rootYoga Yoga.Node.create() buildYogaTree(rootYoga, [json]) // 前两个参数可以传可用宽度和高度传 undefined 表示按子节点内容自适应 rootYoga.calculateLayout(undefined, undefined, Yoga.DIRECTION_LTR) // getComputedLeft / Top 返回的是相对父节点的位置真实实现里要累加父节点 frame const frame { x: rootYoga.getComputedLeft(), y: rootYoga.getComputedTop(), width: rootYoga.getComputedWidth(), height: rootYoga.getComputedHeight() } // 拿到 frame 后再根据 json.type 创建 Sketch.Text 或 Sketch.Rectangle console.log(frame) }这段代码的重点不是能不能直接跑而是整体流程。buildYogaTree负责把 JSON children 递归挂进 Yoga 树calculateLayout负责算布局最后一步从 Yoga 节点取计算后的 frame。参数说明calculateLayout的第一个参数是可用宽度第二个是可用高度第三个是排版方向LTR 表示从左到右。如果你的 JSON 面向阿拉伯语这类从右往左的排版第三个参数要改成Yoga.DIRECTION_RTL。还有一个非常容易踩的细节getComputedLeft()和getComputedTop()返回的是相对父容器的偏移不是全局坐标。递归创建 Sketch 图层时每次都要把父节点的 x、y 累加进去。我见过很多第一次做类似插件的人死在坐标累加这一步最后所有子图层全部叠在画布左上角。3. 安装与接入装进 Sketch 并跑通你的第一条 JSON这个插件的使用门槛不高但很多人卡在第一步拿到的是源码包不知道应该双击还是构建。我一般会先看压缩包根目录有没有manifest.json有就是源码工程先用命令行构建没有就直接找.sketchplugin文件。3.1 两种安装方式双击插件包 vs 源码构建如果你手上的资源已经带.sketchplugin直接双击Sketch 会弹窗确认并把它安装到插件目录。如果没有现成的安装包就要走一遍源码构建。构建本身不复杂两条命令搞定cd json-sketchapp npm install npm run build构建完成后build 目录下会多出一个.sketchplugin文件。用下面这个命令打开 Sketch 的插件安装目录open ~/Library/Application\ Support/com.bohemiancoding.sketch3/Plugins把.sketchplugin文件拖进去或者复制过去Sketch 启动时会自动加载。如果 Sketch 已经开着先退出再重新打开最保险。插件目录里如果已经有同名或同 identifier 的旧版本建议先删掉旧版再拷贝新版避免 Sketch 加载到缓存的旧代码。3.2 准备一份最小 JSON 样本装好插件之后最忌讳的就是拿一大份业务 JSON 去试。先准备一个最小样本确认插件通路正常。我的习惯是从纯文本加矩形开始结构越简单越好{ type: group, name: card, x: 0, y: 0, width: 320, height: 120, children: [ { type: rect, name: background, width: 320, height: 120, style: { backgroundColor: #F5F5F5, cornerRadius: 8 } }, { type: text, name: title, text: Hello json-sketchapp, style: { fontSize: 18, fontWeight: bold, color: #222222 } } ] }这个样本里有两个关键点第一group节点对应 Sketch 的 Group 图层children数组决定图层树层级第二子节点没有手写 x、y坐标由 Yoga 根据容器和样式自动计算。如果你的插件版本不支持自动布局那子节点里就要写相对坐标但从关键词里的 yoga 来看这个项目走的是自动布局路线。实际操作中我发现一个小规律背景矩形和文本同时存在时文本节点最好放在 children 的最后一位这样图层树顺序是背景在下、文字在上不会遮挡。如果插件支持 zIndex就用 zIndex 显式排序别依赖数组顺序。3.3 触发转换并检查结果最小样本准备好后在 Sketch 里执行插件菜单里的命令。命令名每个版本可能不一样最好直接看manifest.json里 commands 下的 name有的版本叫 Import JSON有的叫 JSON to Sketch。点击后 Sketch 一般会弹出文件选择框选中刚才的 demo.json。如果没弹窗可能是从剪贴板读取。插件判断剪贴板里有没有 JSON 字符串有就直接解析。所以当画布上没变化时先把 JSON 文本复制一遍再执行命令。转换成功后画布上会出现一个 card 组里面有背景矩形和一行文本。到这一步再用真实业务数据来试就有一条稳定的基准线了。提示第一次跑通之前不要拿动辄几百行的真实业务 JSON 去试。先用一个矩形加一行文本的最小样本确认通路正常能省掉后面大量排查时间。4. JSON 结构设计坐标、尺寸、文本与嵌套容器当插件能跑通第一条 JSON 后真正影响体验的是你如何组织 JSON 结构。这个插件不是把所有字段平铺一级就完它更接近设计稿的图层树父节点是容器子节点是容器里的内容。4.1 类型映射规则group、text、rect 分别对应什么以常见实现来说JSON 里的 type 字段会映射到 Sketch 图层类别group 映射成 Grouptext 映射成 Textrect 映射成 Rectangleartboard 映射成画板。如果 JSON 里出现插件不认识的类型常见处理是跳过并打印一条警告也有插件会把它当成矩形兜底。用之前最好在源码里搜一下类型分支不要自己发明一堆 type 进去。{ type: text, name: price-label, text: ¥99, frame: { x: 16, y: 10, width: 80, height: 22 }, style: { fontSize: 14, color: #FF4D4F } }这段 JSON 手动指定了 frame适合不需要自动布局的简单场景。如果插件同时支持自动布局和手动 frame小项目用手动 frame 更好控制大列表用自动布局更快。两者混用的时候注意手动 frame 的坐标系和 Yoga 计算结果的坐标系要保持一致否则会出现图层明明有值却叠到一起的情况。4.2 文本、填充、圆角高频字段的写法UI 草稿里出现频率最高的图层就是文本和矩形块我把最常用的字段映射整理成一张表类型JSON 字段对应 Sketch 属性常见错误文本style.fontSizeText 的字号写成font-size文本style.colorText 的文本颜色写十六进制不带#矩形style.backgroundColor填充色只写颜色没写宽高矩形style.cornerRadius圆角把圆角写成radius组style.padding组内边距直接当 frame 坐标用颜色是翻车重灾区。Sketch 内部用 RGBA 存颜色插件通常会把#RRGGBBAA解析成四个通道。如果 JSON 来自 Android 资源文件看到0xFF0000这种格式插件不一定认识。我的习惯是写一段小脚本先把所有0x开头的颜色统一转成#RRGGBB再喂给插件。文本对齐同样容易被忽略。前端习惯写text-align: center插件的属性名可能是alignment取值是 left、center、right。如果你的 JSON 完全按前端习惯写插件又没有做键名映射对齐样式就会被悄悄丢掉。先用清楚插件支持哪些样式字段再决定是改 JSON 还是改插件源码补映射。4.3 用嵌套 JSON 模拟组与画板真实业务很少有扁平结构更多是页面套卡片、卡片套头部、头部套文本这种嵌套。JSON 结构上就是无限递归的 children。根据我拆这个插件的经验嵌套超过四层后只要每层都有 name生成后的图层树依然清晰如果某一层漏了 nameSketch 里会显示成 Group 加数字后缀后面找图层会很难受。{ type: group, name: screen, width: 375, height: 667, children: [ { type: group, name: header, height: 60, children: [ { type: text, name: back, text: , style: { fontSize: 24 } }, { type: text, name: title, text: 详情页, style: { fontSize: 18 } } ] } ] }如果你希望某个嵌套节点生成 Sketch 的 Artboard 而不是普通 Group可以在节点上加artboard: true或者把 type 写成 artboard具体看插件支持哪一种。多页面 JSON 比较适合这种做法一个顶层 group 代表一个页面页面之间用画板隔离后续整理设计稿时比全部塞进同一页清楚得多。5. 避坑与常见问题JSON 转换过程中的四个翻车现场转换类工具容易让人翻车的不是功能有没有而是结果看起来对、实际错得很隐性。下面四个坑是我实际用这个插件时踩过或者看别人踩过的。5.1 坐标整体错位Y 轴方向和单位没统一现象转换出来的元素从画布左上角整体偏移或者所有子图层叠在页面中央看起来像随机摆放。原因常见原因有两个。一是 JSON 里的坐标来自某些 Y 轴向上的平台直接转到 Sketch 后上下颠倒二是单位没统一Sketch 画布用 pt前端导出的 JSON 往往是 px在 2x 屏幕上数值差一倍。解决在 JSON 进入转换前统一换算单位。我一般会写一个normalizeLayout(json, scale)的函数把所有 width、height、x、y 乘以当前 scale 的倒数。如果插件没有提供这个入口就在构建前用 Node 脚本预处理 JSON保证进入插件的已经是 pt 坐标。Y 轴方向的问题同理在递归创建图层时把 y 变成containerHeight - y - height或者先确认输入数据到底是哪个坐标系别在 Sketch 里手动一个个拖回原位。5.2 文本高度差几像素Yoga 算的高度和 Sketch 字体行高对不上现象文本图层的 frame 高度和文字实际高度不一致小字号下尤其明显有时候文字被裁掉一截。原因Yoga 计算高度时通常需要明确的 lineHeight如果 JSON 里没写Yoga 可能拿默认值返回给排版Sketch 的 Text 图层用的又是另一套行高规则。同一个 fontSize 下字体不同、平台不同行高差异少则 2px 多则 5px视觉上一旦叠加圆角背景就会很突兀。解决最直接的办法是在 JSON 的 style 里显式传 lineHeight并让插件在创建 Text 图层时用这个值覆盖 frame.height。如果插件源码里没有读取 lineHeight可以在 style 里加一个自定义字段比如lineHeight: 22再改一行源码让它生效。批量场景下我更推荐生成后到 Sketch 里全选文本图层用“适配高度”统一处理一次但这只适合可手工介入的低频流程。5.3 JSON 解析失败尾逗号、注释和特殊字符现象插件命令执行后没反应Sketch 控制台报 SyntaxError有时候连错误弹窗都不出现。原因很多人把 JSON 和 JS 对象字面量混在一起用直接从 console.log 输出复制 JSON里面要么有注释要么最后一个键后面多了逗号要么字符串用了单引号。JSON.parse 对这些都零容忍一个非法字符整棵解析就会失败。解决在真正执行 JSON.parse 之前先做一次轻量清洗。不想引入额外依赖的话用一段正则就能去掉注释和尾逗号const cleaned raw .replace(/\/\*[\s\S]*?\*\//g, ) .replace(/^\s*\/\/.*$/gm, ) .replace(/,(\s*[}\]])/g, $1) const json JSON.parse(cleaned)这段代码三个 replace 分别处理块注释、行注释和尾逗号。它不能解决所有解析问题但能解决 90% 由手工复制造成的 JSON 解析失败。剩下 10%建议把文本丢给jq .过一遍jq 会直接指出第几行出错比自己猜快很多。5.4 插件构建成功但菜单不出现现象npm run build 正常结束build 目录里也有 .sketchplugin但 Sketch 的 Plugins 菜单里找不到任何 json-sketchapp 相关命令。原因最常见的是 manifest.json 里的 commands 入口文件不存在比如配置写的是 src/import.js但源码被你改成了 importJSON.js另一种可能是插件目录下同时存在两个版本Sketch 加载的是旧插件新插件的菜单名又不一样所以看起来像不生效。解决先打开 build 产物里的 manifest.json检查 commands 数组每个命令的 identifier 和文件路径确认入口文件存在。然后把 Sketch 的插件目录打开看看里面是不是有多个 json-sketchapp 开头的 .sketchplugin有的话只保留一个。最后到 Sketch 的 Preferences Plugins 里查看加载状态有警告标志就点开看报错信息能直接定位问题。6. 进阶把 json-sketchapp 的验证变成习惯不再盲转这个插件最适合的定位是草稿生成器不是最终设计稿生成器。所以真正好用的方式是先把验证做在前头而不是转换完就急着拖图层调样式。我把每次转换后的验证固定在三个维度图层树结构、frame 数值、文本样式。图层树看层级有没有丢frame 看随机抽两个节点的坐标和尺寸是否符合预期文本样式看字体大小和颜色有没有被错误忽略。三个维度都没有问题这次转换才算通过。如果需要快速确认一次转换有没有生成完整文件可以在命令行里把 .sketch 拆开看。Sketch 文件本质上是一个 zip 包结构上包含画板、图层、样式资源。用下面这组命令就能看到大概cp demo.sketch demo.zip unzip -q demo.zip -d demo_unzip find demo_unzip -name *.json | head -20这组命令能帮你判断输出不是空文件但别把它当成完整校验手段。页面内的坐标和样式编码在更深层的数据里真正要验证 frame还是在 Sketch 里选中图层看检查器更直接。如果插件暴露了 headless 或命令行入口可以把它接进前端工作流JSON 一更新自动生成一版 .sketch 文件。常见做法是挂在 git pre-commit 钩子上代码提交前先生成一次设计文件让评审的人拿到的是可打开的产物。没有 headless 入口的版本就保持手工触发不值得为了省两步操作强行改插件造成不稳定。如果你也在做这类重复布局建议把 json-sketchapp 的源码或现成插件包找下来跑一遍比只看示例图有用得多。从那以后我每次用 json-sketchapp 都强制走一遍“图层树数量、随机 frame、文本样式”这三步验证发现异常先回 JSON 侧修而不是在 Sketch 里手动拖图层。这个插件最有价值的地方不是省掉手动画框的时间而是逼着我把界面结构写成可复现的数据把一次性的手工操作变成能重复执行的流程。希望帮到你。本文还有配套的精品资源点击获取