ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

复古车票的字段与装饰条码

复古车票的字段与装饰条码

复古车票很适合做旅行札记封面:站名、日期、座位,各自占一小块纸面。真正做成工具时,先要回答一个朴素问题——用户改了字段,下载的文件会不会跟着变?如果页面看起来能编辑,导出却仍是默认站名,装饰就掩盖了功能缺口。

一份数据,同时生成预览与文件

我把车票当作结构化数据:出发站、到达站、日期、座位。校验完成后只生成一份 SVG 字符串,预览和下载使用同一份内容。这样至少不会出现“屏幕是成都,文件里还是上海”的双份状态。

日期应检查真实日历,不能只匹配四位数、两位数、两位数:2026-02-30也符合那个正则。下面用 UTC 日期回转检查;这是没有时刻含义的票面日期,不拿用户时区猜测出发时间。站名限制长度并转义 XML,既避免撑破版式,也防止用户输入变成额外标签。

条纹只当条纹

底部黑白条纹由固定数组画出,明确写着“装饰条纹,不可检票”。它不是 Code 39、二维码或真实订单号。一个随意排列的黑条图案,即使很像条码,也不能宣称被扫码器读取。若产品真的需要机器可读编码,应选定标准、编码库和实际扫描测试,另作实现。

SVG 路径与图形规范为矢量导出提供了明确的几何语义,但不替应用完成字段检查。例子在 Node 中生成ticket.svg,可用支持 SVG 的查看器打开;没有调用订票服务,没有产生真实车票或购买凭证。

本地验证包含闰日、非法日期、XML 特殊字符,以及导出内容确实包含用户输入。浏览器交互、下载手势与字体效果还需要界面测试。对这类小工具,我会先保证“你填的,就是你拿走的”,再给纸边加一圈旧旧的毛刺。

可独立运行的核心例子

const fs=require('node:fs'); const esc=s=>s.replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&apos;'}[c])); function dateOK(s) { if(!/^20\d\d-\d\d-\d\d$/.test(s)) return false; const d=new Date(s+'T00:00:00Z'); return Number.isFinite(d.getTime()) && d.toISOString().slice(0,10)===s; } function ticket({from,to,date,seat}) { for(const s of [from,to,seat]) if(typeof s!=='string'||!s.trim()||[...s].length>12) throw Error('字段需1..12字'); if(!dateOK(date)) throw Error('日期不存在或超出2000..2099'); const labels=[`${from} → ${to}`,date,`座位 ${seat}`]; let x=30; const bars=[3,1,2,4,1,3,2,1,4,2,3,1].map(w=>{ const out=`<rect x="${x}" y="142" width="${w*2}" height="22"/>`;x+=w*2+4;return out; }); return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 500 200"> <rect width="500" height="200" rx="12" fill="#f1e2c8"/> ${labels.map((s,i)=>`<text x="30" y="${38+i*36}" font-size="24">${esc(s)}</text>`).join('')} ${bars.join('')}<text x="30" y="188" font-size="12">装饰条纹,不可检票</text></svg>`; } if(dateOK('2026-02-30')||!dateOK('2028-02-29')) throw Error('日期校验失败'); const s=ticket({from:'成都',to:'山间<&',date:'2026-10-24',seat:'07A'}); if(!s.includes('山间&lt;&amp;')||!s.includes('07A')) throw Error('字段未进入导出'); fs.writeFileSync('ticket.svg',s);console.log('已生成 ticket.svg');

返回列表