上传后「原始尺寸」和源文件写的不一样
拿一枚 <svg viewBox="0 0 24 24"> 试预览,「原始尺寸」写着 24 × 24 px,可预览框里那圈图形撑满了比它大得多的区域;换成把宽高写成 480 的,读数跟着变 480 × 480 px,框却没变。两个数各走各的——这个页面有两套尺寸口径。
「原始尺寸」这一栏只按回退链读数
这个页面是 SVG图片预览,它的 renderSvg 兵分两路。一路喂进 DOMParser 只算「原始尺寸」:先看根标签的 width、height 属性,缺位才取 viewBox 第 3、4 段,viewBox 也没有就写死 300,最后 parseFloat 取 Math.round 拼成「N × M px」。另一路把节点插进预览框,先把 width、height 改成 100%,再 removeAttribute('viewBox')。两条路数值互不传递,读数与画出来的框经常对不上。
| 根标签写法 | 「原始尺寸」读数 | 实际显示框 |
|---|---|---|
| width=200 height=100 | 200 × 100 px | 600×400 |
| 只有 viewBox 0 0 24 24 | 24 × 24 px | 600×400 |
| width=480 与 viewBox 冲突 | 480 × 480 px | 600×400 |
| 宽高与 viewBox 都缺 | 300 × 300 px | 600×400 |
| 只写 style width:200px height:150px | 300 × 300 px | 200×150 |
前四行里,源文件写 200、24 还是 480 都一样:viewBox 被删、宽高强制 100% 后,真节点外框等于预览容器——探针容器固定 600.00×400.00,实测每行都落在这个值。只有最后一行例外:宽高写进行内 style 时,200px、150px 压过铺上去的 100%,实测框才是 200.00×150.00。「原始尺寸」栏从来不是显示框尺寸,它是回退读数。
图 1:「原始尺寸」读数与实际显示框的两套口径
删掉 viewBox 之后,r=1 的圆永远是 2 像素
viewBox 本来把用户坐标映射到视口,被 removeAttribute 之后,用户坐标与 CSS 像素 1:1 落地,图形多大只由自身数字说了算。同一枚 <circle r="1"> 塞进 24 单位、480 单位、冲突、什么都不写、嵌套这五种源,走 renderSvg 后直径实测全是 2.00×2.00。可若不删 viewBox、按原生方式在同一 600×400 框里渲染,r=1 在 viewBox="0 0 24 24" 下量到 33.33×33.33、在 viewBox="0 0 480 480" 下量到 1.67×1.67,原生口径下相差约 20 倍。删掉 viewBox 把这 20 倍差距拉平成同一个 2.00。
缩放每档 0.2、夹在 20% 到 500%,「适应」其实是复位
zoomSvg 每次加减 0.2,再把 svgZoom 夹住,倍率停在 20% 到 500%:从 1 起连点放大是 1.2、1.4、1.6,到 500% 后原样不动;连点缩小到 20% 也不再变。写着「适应」的按钮,fit 分支无视当前倍率、直接把 svgZoom 设回 1,即复位成 100%,不是贴合窗口。读数用 Math.round(svgZoom*100),浮点 1.5999… 显示 160%(截断会是 159%)、4.999… 显示 500%(截断会是 499%),是四舍五入不是截断。
「SVG 源码」里的缩进,其实只在开标签前插换行
源码 Tab 是 formatSourceCode 的产物,名字挂着「缩进」,实测它只在每个开标签前插一个换行再上三色高亮,不补缩进空格、不改属性顺序、不拆自闭合。那枚 121 字符的单行样本,换行阶段变 6 行、129 字符,加上转义与高亮后 innerHTML 达 950 字符。
近半兆的大文件,代码里没有任何上限守卫
一份 498635 字节、约 0.47MB、单行铺满 12000 个 rect 的大 SVG 喂进去,renderSvg 耗时 308 毫秒跑完,元素数量统计成 12001,显示框仍是 600×400。这个 12001 是正则 /<\w+/g 逐个匹配开标签样式计出的,即 1 个 svg 加 12000 个 rect,闭合标签与注释不计。代码里既无字节上限也无元素上限守卫,大文件不会被拦下。
失败路径与文案对照
失败提交都在清空预览前提前 return,旧预览原样留着。输入框为空弹「请上传 SVG 文件或粘贴代码」;丢一段没标签的文本、或一个没闭合的 <svg width="10" height="10",取不到 svg 节点弹「未找到有效的 SVG 标签」。带 BOM 的会被 trim 剥掉照常解析;GBK 字节文件端到端未实测,只能确认 readAsText 未传编码参数、默认按 UTF-8 解码,ASCII 标签仍能解析。内联脚本对照:塞进 <script> 经 innerHTML 注入后节点插入(计数 1)但不执行;<image> 只测 data: 与本地相对路径两种 href,节点存活,像素是否真正解码未据此断言,全程不指向任何外部主机。
页面说法与实测对照,config 介绍共 6 条可判定:上传预览、纯前端不上传两条一致;代码高亮、基本信息、缩放查看三条部分一致——高亮其实只有换行、尺寸是回退读数、缩放被夹在 20% 到 500%。对不上的是那句「实时渲染」:代码没有任何 input、paste、keyup 监听去触发 renderSvg,只有「渲染预览」按钮和文件 readAsText 回调两条触发,粘贴完不点按钮画面不会变。
FAQ
Q:为什么信息栏尺寸和预览框里看到的不一样?
两套数。「原始尺寸」走 width/height→viewBox→300 回退读数,显示框被强制 100% 且删了 viewBox,恒等于容器。想知道画多大看预览框本身。
Q:那个「适应」按钮能让图铺满窗口吗?
不能。fit 分支只把倍率复位成 100%,不是贴合窗口。放大每点一次加 0.2,最多到 500%。
Q:预览里的圆忽大忽小,是不是 viewBox 写错了?
不是 viewBox 写错。是预览在注入前删了 viewBox,坐标按 1:1 落地,r=1 恒定 2 像素。至于把 SVG 转成图片、外部字体或图片在这类处理里怎么被丢,是另两条话题,分别见旧文 SVG 转 PNG 的导出尺寸 与 SVG 的外部字体与外链图片。