基于 Vue3 + Canvas 实现教师版 MBTI 人格测试:五维模型、彩蛋机制与海报生成技术实践
# 基于 Vue3 Canvas 实现教师版 MBTI 人格测试## 项目背景拾趣课堂shiqu.fun是一个面向中小学教师的免费课堂工具平台。其中「教师版 MBTI 人格测试」模块是一个独立的互动测评工具需要实现场景化问卷、多维度人格匹配、结果可视化海报生成等功能。本文分享这个模块的核心技术实现。## 技术栈| 层 | 技术选型 ||----|---------|| 前端框架 | Vue 3 TypeScript Inertia.js || UI 组件 | shadcn-vue || 样式 | Tailwind CSS 4 || 数据可视化 | Canvas API原生绘制 || 后端 | Laravel 12 || 埋点 | 自建事件追踪MbtiTrackController || 配置管理 | 外部 JS 配置文件window 挂载 |## 五维人格模型设计传统 MBTI 使用 4 个二元维度E/I、S/N、T/F、J/P教师版采用 5 个连续维度typescripttype TeacherMbtiLevel L | M | Hinterface DimensionScore {d1: number // 圣母指数 — 共情·耐心·情感投入d2: number // 结界指数 — 工作与生活的边界感d3: number // 强迫指数 — 计划性·条理·规则感d4: number // 脸皮厚度 — 情绪弹性·自愈力d5: number // 整活指数 — 灵活变通·教学创新}每个维度的原始分值映射为 L低/ M中/ H高三个等级最终形成一个 5 位模式码如 HLMHM与预设的 18 个人格模式进行距离匹配。## 人格匹配算法核心逻辑是将用户的五维等级码与 18 个预设模式计算距离取最小距离的人格作为匹配结果typescript// 简化示意interface PersonalityPattern {code: string // 如 PPTpattern: string // 如 LHHLM五维等级模式weight?: number[] // 各维度权重}function matchPersonality(userLevels: string, patterns: PersonalityPattern[]) {return patterns.map(p ({...p,distance: calcWeightedDistance(userLevels, p.pattern, p.weight),accuracy: calcAccuracy(userLevels, p.pattern)})).sort((a, b) a.distance - b.distance)[0]}距离计算使用加权曼哈顿距离其中 L0, M1, H2。每个人格模式可以定义各维度的权重使得某些人格对特定维度更敏感。## 隐藏人格彩蛋机制25 道标准题之外配置中包含 2 道隐藏触发题。彩蛋触发采用条件评估机制javascript// config.js 中的隐藏题配置示意{id: hidden_1,trigger: { dimension: d3, threshold: H },options: [{ value: 3, kicker: PE } // 选择该选项 → 触发隐藏人格 PE]}触发条件1. 在标准答题过程中某个关键维度达到阈值2. 系统插入隐藏题3. 用户在隐藏题中选择了特定选项4. 跳过正常匹配直接返回隐藏人格教师版的隐藏人格是 **PE被占课体质**幼教版是 **GLUE全园万能胶**。## 双版本配置架构教师版和幼教版通过独立的配置文件实现public/mbti/js/├── config.js ← window.TeacherTest└── config-kindergarten.js ← window.KindergartenTest前端通过版本参数动态加载对应配置typescripttype TeacherMbtiVersion teacher | kindergarten// 根据版本加载不同窗口对象const config version teacher? window.TeacherTest: window.KindergartenTest角色系统也随版本切换- 教师版BZR班主任/ FBZ非班主任- 幼教版ZB主班/ PB配班部分题目的 alt 字段会根据角色展示不同的问法。## Canvas 海报生成测试结果页面提供「保存海报」功能使用 Canvas API 绘制五维雷达图和人格信息typescriptfunction drawRadarChart(ctx: CanvasRenderingContext2D, scores: number[]) {const center { x: 200, y: 200 }const radius 150const dims 5const angleStep (Math.PI * 2) / dims// 绘制五边形网格for (let level 1; level 3; level) {ctx.beginPath()for (let i 0; i dims; i) {const r (radius / 3) * levelconst x center.x r * Math.cos(angleStep * i - Math.PI / 2)const y center.y r * Math.sin(angleStep * i - Math.PI / 2)i 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y)}ctx.closePath()ctx.stroke()}// 绘制数据区域ctx.beginPath()scores.forEach((score, i) {const r (radius / 3) * score // score 为 1-3const x center.x r * Math.cos(angleStep * i - Math.PI / 2)const y center.y r * Math.sin(angleStep * i - Math.PI / 2)i 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y)})ctx.closePath()ctx.fillStyle rgba(99, 102, 241, 0.3)ctx.fill()}海报还包含人格名称、Emoji、标语文案和分享二维码导出为 PNG 供用户下载。## 进度持久化使用 localStorage 保存答题进度支持用户中途退出后恢复typescriptconst STORAGE_KEY shiqu:mbti:progressinterface MbtiProgress {version: TeacherMbtiVersionrole: stringcurrentIndex: numberanswers: Recordstring, numbertimestamp: number}读取时检查版本一致性不同版本的进度互不干扰。## 事件埋点自建埋点系统追踪完整用户旅程page_view → test_start → test_complete → share_click后端 MbtiTrackController 接收事件数据记录访客 ID、设备类型、UTM 参数和业务数据人格类型、匹配度、版本等。## URL 哈希分享结果使用 URL 哈希实现永久链接- 教师版/tools/mbti#type/PPT- 幼教版/tools/mbti#ktype/MAMA哈希变化不触发页面刷新前端监听 hashchange 事件加载对应人格数据。分享链接可以跨平台传播微信内也能正常打开。## 小结这个模块的技术要点1. 五维连续模型替代四维二元模型匹配精度更高2. 隐藏触发机制增加了测试趣味性和传播性3. Canvas 原生绘制海报无需依赖第三方图表库4. 双版本配置文件架构实现内容完全独立代码完全复用5. localStorage 进度持久化 URL 哈希分享实现了良好的用户体验项目地址拾趣课堂 https://sqkt.syhmai.com/教师版 MBTI 测试入口在「工具」页面。 免费使用https://sqkt.syhmai.com/