Files
mama-box/topic/ceshi/index.html

795 lines
55 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<!-- 11-04 UGC 总开关关着时本页不展示,直接回首页(js/ugc.js) -->
<script src="../../js/ugc.js?v=26110420" data-guard></script>
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover">
<meta name="format-detection" content="telephone=no">
<title>测一测你是什么样的妈妈?</title>
<!-- 孕期专题 · 趣味测试(孕期首页「其他妈妈也在搜」第 2 条入口)。
2026-10-31 v3:按《孕期专题页设计规范 v3》重做成「妈妈类型卡」——主色 #7C5CFC、浅底 #F1EDFF。
一页三屏:开始 / 答题(一题一屏,左右滑动)/ 结果(类型卡 + 雷达 + 结合作答的解读 + 按类型推荐工具 + 保存结果卡)。
结果存 localStorage「mmbox.ceshi.v3」(含每题作答,刷新后解读可复现;题目已重写,不复用 v2)。
插画复用 img/*.webp(hero + 4 种类型同一画风)。自成一页:不引 app.js;返回走 history 或相对路径 ../../,
推荐工具走 ../_shared/tools.js(同源 /<slug>/,带 search + hash)。
纯娱乐,不采集、不上报答题数据。「已有 N 位妈妈测过」没有真实数据源,按 AGENTS.md 第 2/12 条不造数字:TESTED_COUNT=0 时不显示。 -->
<style>
:root{--c:#7C5CFC;--cbg:#F1EDFF;--c06:rgba(124,92,252,.06);--c10:rgba(124,92,252,.10);--c20:rgba(124,92,252,.20);--ink:#1F2329;--txt:#4E5969;--sub:#86909C;--line:#EEF0F3;--soft:#F7F8FA}
*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}
html,body{height:100%;overflow:hidden;background:#fff;color:var(--txt);font:15px/1.75 -apple-system,BlinkMacSystemFont,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif}
#scroll{position:fixed;inset:0;overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;overscroll-behavior:none;padding-bottom:calc(24px + env(safe-area-inset-bottom))}
img{display:block;max-width:100%}
button{font:inherit;border:0;background:none;color:inherit;cursor:pointer}
.ic{width:20px;height:20px;flex:none;fill:none;stroke:currentColor;stroke-width:1.8;stroke-linecap:round;stroke-linejoin:round}
.hide{position:absolute;width:0;height:0;overflow:hidden}
[hidden]{display:none !important}
.num{font-variant-numeric:tabular-nums}
mark{background:linear-gradient(transparent 62%,var(--c20) 0);color:inherit;padding:0 1px}
/* 顶栏 */
.bar{position:sticky;top:0;z-index:20;display:flex;align-items:center;gap:4px;height:48px;padding:0 8px;padding-top:env(safe-area-inset-top);background:transparent;border-bottom:1px solid transparent;transition:background .2s,border-color .2s}
.bar.sh{background:#fff;border-bottom-color:var(--line)}
.bar .back{width:36px;height:36px;border-radius:50%;display:grid;place-items:center;color:var(--ink)}
.bar .back .ic{width:22px;height:22px}
.bar .t{font-weight:600;font-size:16px;color:var(--ink)}
/* 三屏 */
.view{display:none}
.view.on{display:block;animation:vin .35s ease both}
@keyframes vin{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:none}}
.wrap{padding:0 20px}
.btn{display:flex;align-items:center;justify-content:center;gap:6px;width:100%;height:46px;border-radius:99px;font-size:16px;font-weight:700;transition:transform .15s,opacity .15s}
.btn.pri{background:var(--c);color:#fff;box-shadow:0 6px 16px rgba(124,92,252,.28)}
.btn.sec{background:#fff;color:var(--c);border:1px solid var(--c)}
.btn:active,.tap:active{transform:scale(.98)}
/* 区块标题:小号序号 + 标题 */
.sh2{display:flex;align-items:baseline;gap:8px;margin-bottom:14px}
.sh2 i{font-style:normal;font-size:13px;font-weight:800;color:var(--c);letter-spacing:.5px}
.sh2 b{font-size:18px;font-weight:800;color:var(--ink);line-height:1.4}
.sh2 span{margin-left:auto;font-size:12.5px;color:var(--sub)}
/* ---------- ① 开始 ---------- */
#vStart{margin-top:-48px}
.hero{position:relative;overflow:hidden;min-height:430px;padding:72px 20px 0;background:linear-gradient(160deg,var(--cbg) 0%,#fff 72%)}
.hero .o1,.hero .o2{position:absolute;border-radius:50%;background:var(--c10);pointer-events:none}
.hero .o1{width:260px;height:260px;right:-90px;top:-70px}
.hero .o2{width:150px;height:150px;left:-60px;bottom:40px;background:var(--c06)}
.hero .eb{position:relative;display:inline-flex;align-items:center;gap:6px;height:26px;padding:0 12px;border-radius:99px;background:#fff;color:var(--c);font-size:12.5px;font-weight:700;letter-spacing:.5px;box-shadow:0 2px 8px var(--c10)}
.hero h1{position:relative;margin-top:16px;font-size:30px;font-weight:800;line-height:1.32;color:var(--ink);letter-spacing:.5px}
.hero .meta{position:relative;display:flex;flex-direction:column;gap:8px;margin-top:18px;width:150px}
.hero .meta span{display:flex;align-items:center;gap:6px;font-size:13.5px;color:var(--txt);line-height:1.4}
.hero .meta .ic{width:18px;height:18px;color:var(--c)}
.hero .meta b{color:var(--ink);font-weight:800}
.hero .pic{position:absolute;right:-18px;bottom:0;width:min(228px,calc(100vw - 162px));height:min(228px,calc(100vw - 162px));object-fit:cover;object-position:center 30%;border-radius:28px 0 0 0;box-shadow:0 8px 24px var(--c10)}
.types{margin-top:28px}
.tgrid{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.tcard{display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:18px;background:var(--soft)}
.tcard img{flex:none;width:46px;height:46px;border-radius:50%;object-fit:cover;object-position:center 22%;border:2px solid #fff;box-shadow:0 2px 8px var(--c10)}
.tcard b{display:block;font-size:14.5px;color:var(--ink);line-height:1.35}
.tcard small{display:block;font-size:12px;color:var(--sub);line-height:1.4}
.startbox{margin-top:28px;text-align:center}
.startbox .note{margin-top:10px;font-size:12.5px;color:var(--sub)}
/* ---------- ② 答题 ---------- */
#vQuiz{padding-top:4px}
.qtop{display:flex;align-items:center;justify-content:space-between;height:34px}
.qtop button{display:inline-flex;align-items:center;gap:2px;font-size:13.5px;color:var(--sub);padding:4px 8px 4px 0}
.qtop button .ic{width:16px;height:16px}
.qtop button:disabled{visibility:hidden}
.qtop .no{font-size:13px;color:var(--sub)}
.qtop .no b{font-size:18px;color:var(--c);font-weight:800}
.feet{display:flex;justify-content:space-between;align-items:center;height:30px;margin-top:4px;padding:0 2px}
.feet svg{width:15px;height:15px;fill:#E4DDFD;transition:fill .3s,transform .3s}
.feet svg:nth-child(odd){transform:translateY(-4px) rotate(-12deg)}
.feet svg:nth-child(even){transform:translateY(4px) rotate(12deg) scaleX(-1)}
.feet svg.done{fill:var(--c)}
.feet svg.cur{fill:var(--c)}
.feet svg.cur:nth-child(odd){transform:translateY(-4px) rotate(-12deg) scale(1.35)}
.feet svg.cur:nth-child(even){transform:translateY(4px) rotate(12deg) scaleX(-1) scale(1.35)}
.stage{margin-top:14px;transition:opacity .22s ease,transform .22s ease}
.stage.outL{opacity:0;transform:translateX(-36px)}
.stage.outR{opacity:0;transform:translateX(36px)}
.stage.inR{opacity:0;transform:translateX(36px);transition:none}
.stage.inL{opacity:0;transform:translateX(-36px);transition:none}
.qcard{position:relative;overflow:hidden;padding:20px 20px 18px;border-radius:24px;background:linear-gradient(160deg,var(--cbg),#fff 78%);box-shadow:0 8px 24px var(--c10)}
.qcard:after{content:"";position:absolute;width:120px;height:120px;right:-40px;top:-40px;border-radius:50%;background:var(--c10)}
.qcard .hd{position:relative;display:flex;align-items:center;justify-content:space-between}
.qcard .qi{width:56px;height:56px;border-radius:18px;display:grid;place-items:center;background:#fff;color:var(--c);box-shadow:0 4px 12px var(--c10)}
.qcard .qi .ic{width:30px;height:30px;stroke-width:1.6}
.qcard .cat{position:relative;z-index:1;height:24px;padding:0 10px;border-radius:99px;background:#fff;color:var(--c);font-size:12px;font-weight:700;line-height:24px}
.qcard h2{position:relative;margin-top:16px;font-size:21px;font-weight:800;line-height:1.45;color:var(--ink);min-height:61px;text-wrap:balance}
.opts{display:flex;flex-direction:column;gap:10px;margin-top:16px}
.opt{position:relative;display:flex;align-items:center;gap:12px;width:100%;min-height:56px;padding:11px 46px 11px 14px;border-radius:18px;background:#fff;border:1.5px solid var(--line);text-align:left;font-size:15.5px;line-height:1.45;color:var(--ink);transition:border-color .2s,background .2s,transform .15s}
.opt:active{transform:scale(.98)}
.opt .l{flex:none;width:26px;height:26px;border-radius:9px;display:grid;place-items:center;background:var(--soft);color:var(--sub);font-size:13px;font-weight:800;transition:background .2s,color .2s}
.opt .ck{position:absolute;right:14px;top:50%;width:22px;height:22px;margin-top:-11px;border-radius:50%;background:var(--c);color:#fff;display:grid;place-items:center;transform:scale(0);transition:transform .25s cubic-bezier(.3,1.6,.5,1)}
.opt .ck .ic{width:14px;height:14px;stroke-width:2.6}
.opt.sel{border-color:var(--c);background:#FBFAFF;font-weight:600}
.opt.sel .l{background:var(--c);color:#fff}
.opt.sel .ck{transform:scale(1)}
.qtip{margin-top:16px;text-align:center;font-size:12.5px;color:var(--sub)}
/* ---------- ③ 结果 ---------- */
#vResult{padding-top:6px}
.rcard{position:relative;overflow:hidden;padding:22px 20px 18px;border-radius:28px;background:linear-gradient(170deg,#E9E2FF 0%,#F6F3FF 44%,#fff 100%);box-shadow:0 8px 24px var(--c10);text-align:center}
.rcard .o1,.rcard .o2{position:absolute;border-radius:50%;pointer-events:none}
.rcard .o1{width:220px;height:220px;right:-80px;top:-60px;background:rgba(255,255,255,.55)}
.rcard .o2{width:140px;height:140px;left:-50px;top:150px;background:var(--c06)}
.rcard .top{position:relative;display:flex;justify-content:space-between;align-items:center;font-size:12px;line-height:24px}
.rcard .top b{padding:0 10px;border-radius:99px;background:#fff;color:var(--c);font-weight:700}
.rcard .top span{color:var(--sub)}
.rcard .ava{position:relative;width:172px;height:172px;margin:14px auto 0;border-radius:32px;overflow:hidden;border:5px solid #fff;box-shadow:0 8px 24px var(--c10)}
.rcard .ava img{width:100%;height:100%;object-fit:cover;object-position:center 30%}
.rcard .you{position:relative;margin-top:14px;font-size:13px;color:var(--sub);letter-spacing:2px}
.rcard h1{position:relative;font-size:28px;font-weight:800;line-height:1.3;color:var(--ink)}
.rcard .slo{position:relative;margin-top:6px;font-size:14.5px;color:var(--txt);line-height:1.6}
.rtags{position:relative;display:flex;justify-content:center;gap:8px;margin-top:14px}
.rtags span{height:30px;padding:0 12px;border-radius:99px;background:#fff;color:var(--c);font-size:13.5px;font-weight:700;line-height:30px;white-space:nowrap;box-shadow:0 2px 8px var(--c10)}
.dims{position:relative;display:flex;align-items:center;gap:12px;margin-top:18px;padding:14px 14px 14px 8px;border-radius:20px;background:rgba(255,255,255,.85);text-align:left}
.dims svg{flex:none;width:146px;height:128px}
.dl{flex:1;min-width:0;display:flex;flex-direction:column;gap:9px}
.dr{display:grid;grid-template-columns:1fr auto;align-items:center;row-gap:3px;font-size:12.5px;color:var(--txt);line-height:1.3}
.dr .p{font-weight:700;color:var(--ink)}
.dr .tr{grid-column:1/3;height:5px;border-radius:5px;background:#EFEAFF;overflow:hidden}
.dr .tr i{display:block;height:100%;width:0;border-radius:5px;background:#C7B9FE;transition:width .8s cubic-bezier(.3,.7,.2,1)}
.dr.me{color:var(--c);font-weight:700}
.dr.me .p{color:var(--c)}
.dr.me .tr i{background:var(--c)}
.rcard .brand{position:relative;margin-top:14px;font-size:11.5px;color:var(--sub);letter-spacing:.5px}
.racts{display:flex;gap:10px;margin-top:16px}
.racts .btn{flex:1;font-size:15px}
.blk{margin-top:36px}
.read{padding:18px;border-radius:24px;background:var(--soft)}
.read p{font-size:15px;line-height:1.8;color:var(--txt)}
.read p+p{margin-top:10px}
.read b{color:var(--ink)}
.read q{quotes:"「" "」";color:var(--c);font-weight:700}
.tips{display:flex;flex-direction:column;gap:10px}
.tp{display:flex;gap:14px;align-items:flex-start;padding:14px 16px;border-radius:18px;background:#fff;border:1px solid var(--line)}
.tp .n{flex:none;width:30px;font-size:30px;font-weight:800;line-height:1;color:transparent;-webkit-text-stroke:1.4px var(--c);font-variant-numeric:tabular-nums}
.tp p{font-size:14.5px;line-height:1.65;color:var(--ink)}
.mate{display:flex;align-items:center;gap:14px;padding:14px 16px;border-radius:24px;background:linear-gradient(110deg,var(--cbg),#fff 80%)}
.mate img{flex:none;width:60px;height:60px;border-radius:50%;object-fit:cover;object-position:center 22%;border:3px solid #fff;box-shadow:0 4px 12px var(--c10)}
.mate small{display:block;font-size:12px;color:var(--sub);line-height:1.5}
.mate b{display:block;font-size:16px;color:var(--ink);line-height:1.4}
.mate p{margin-top:2px;font-size:13.5px;color:var(--txt);line-height:1.55}
#tools{margin-top:36px !important}
.again{margin-top:24px}
.foot{margin:28px 20px 0;font-size:12px;color:var(--sub);text-align:center}
.toast{position:fixed;left:50%;bottom:calc(80px + env(safe-area-inset-bottom));transform:translate(-50%,8px);max-width:300px;padding:10px 16px;border-radius:12px;background:rgba(31,35,41,.88);color:#fff;font-size:13.5px;line-height:1.6;text-align:center;opacity:0;pointer-events:none;transition:opacity .2s,transform .2s;z-index:60}
.toast.on{opacity:1;transform:translate(-50%,0)}
/* 保存结果卡弹层 */
.mask{position:fixed;inset:0;z-index:50;display:none;flex-direction:column;align-items:center;justify-content:center;padding:24px 28px calc(24px + env(safe-area-inset-bottom));background:rgba(20,16,40,.82)}
.mask.on{display:flex;animation:vin .25s ease both}
.mask img{max-width:100%;max-height:calc(100% - 96px);border-radius:16px;box-shadow:0 12px 32px rgba(0,0,0,.25);-webkit-touch-callout:default;user-select:auto}
.mask p{margin-top:14px;color:#fff;font-size:14.5px;font-weight:600;display:flex;align-items:center;gap:6px}
.mask .row{display:flex;gap:16px;margin-top:10px}
.mask .row button,.mask .row a{height:34px;padding:0 18px;border-radius:99px;border:1px solid rgba(255,255,255,.6);color:#fff;font-size:13.5px;line-height:32px;text-decoration:none}
.fade{opacity:0;transform:translateY(12px);transition:opacity .45s ease,transform .45s ease}
.fade.in{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){.fade,.stage,.view.on,.mask.on{opacity:1;transform:none;transition:none;animation:none}}
</style>
</head>
<body>
<!-- 单色线性图标(每题一个场景图标 q-*) -->
<svg class="hide" aria-hidden="true" xmlns="http://www.w3.org/2000/svg">
<symbol id="i-back" viewBox="0 0 24 24"><path d="M15 5l-7 7 7 7"/></symbol>
<symbol id="i-arrow" viewBox="0 0 24 24"><path d="M5 12h13M13 6.5l5.5 5.5-5.5 5.5"/></symbol>
<symbol id="i-check" viewBox="0 0 24 24"><path d="M5 12.5l4.5 4.5L19 7.5"/></symbol>
<symbol id="i-clock" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8.5"/><path d="M12 7.5V12l3 2"/></symbol>
<symbol id="i-list" viewBox="0 0 24 24"><path d="M9 6.5h10M9 12h10M9 17.5h10M4.5 6.5h.01M4.5 12h.01M4.5 17.5h.01"/></symbol>
<symbol id="i-lock" viewBox="0 0 24 24"><rect x="5" y="10.5" width="14" height="10" rx="3"/><path d="M8.5 10.5V8a3.5 3.5 0 0 1 7 0v2.5"/></symbol>
<symbol id="i-down" viewBox="0 0 24 24"><path d="M12 4v11M7.5 11l4.5 4.5 4.5-4.5M5 19.5h14"/></symbol>
<symbol id="i-copy" viewBox="0 0 24 24"><rect x="8.5" y="8.5" width="11.5" height="11.5" rx="2.5"/><path d="M15.5 8.5V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7.5a2 2 0 0 0 2 2h2.5"/></symbol>
<symbol id="i-refresh" viewBox="0 0 24 24"><path d="M20 12a8 8 0 1 1-2.4-5.7M20 4v4.5h-4.5"/></symbol>
<symbol id="i-hand" viewBox="0 0 24 24"><path d="M9 11V5.5a1.5 1.5 0 0 1 3 0V10M12 9.5V4.5a1.5 1.5 0 0 1 3 0V10M15 9.5V6a1.5 1.5 0 0 1 3 0v8a6.5 6.5 0 0 1-6.5 6.5h-.6a6 6 0 0 1-4.6-2.2L4 15.5a1.6 1.6 0 0 1 2.4-2.1L9 15.5V11"/></symbol>
<symbol id="i-foot" viewBox="0 0 24 24"><path d="M12 9c3 0 4.6 2.7 4.6 6.3S14.8 22 12 22s-4.6-3.1-4.6-6.7S9 9 12 9z"/><circle cx="7.6" cy="6.6" r="1.6"/><circle cx="10.6" cy="4.4" r="1.75"/><circle cx="14" cy="4.6" r="1.6"/><circle cx="16.8" cy="6.8" r="1.35"/></symbol>
<!-- 题目场景 -->
<symbol id="q-test" viewBox="0 0 24 24"><rect x="9" y="2.5" width="6" height="19" rx="3"/><path d="M9 9h6M9 15.5h6M11 11.5v2M13 11.5v2"/></symbol>
<symbol id="q-board" viewBox="0 0 24 24"><rect x="5" y="4.5" width="14" height="17" rx="2.5"/><path d="M9 3h6v3H9zM8.5 11l1.5 1.5 3-3M8.5 16.5h7"/></symbol>
<symbol id="q-wait" viewBox="0 0 24 24"><path d="M7 3h10M7 21h10M8 3c0 4.5 4 5.5 4 9s-4 4.5-4 9M16 3c0 4.5-4 5.5-4 9s4 4.5 4 9M10 18.5h4"/></symbol>
<symbol id="q-moon" viewBox="0 0 24 24"><path d="M19.5 14.5A8 8 0 1 1 9.5 4.5a6.5 6.5 0 0 0 10 10z"/><path d="M16 4v3M14.5 5.5h3"/></symbol>
<symbol id="q-scale" viewBox="0 0 24 24"><rect x="3.5" y="4" width="17" height="16" rx="4"/><path d="M8 11a4 4 0 0 1 8 0M12 11l2-2.2"/></symbol>
<symbol id="q-phone" viewBox="0 0 24 24"><rect x="6" y="2.5" width="12" height="19" rx="3"/><path d="M10.5 18.5h3M12 7v4.5M12 14h.01"/></symbol>
<symbol id="q-bowl" viewBox="0 0 24 24"><path d="M3.5 11.5h17a8.5 8.5 0 0 1-17 0zM9 20h6M14 8.5l5-5M17 8.5l3-3"/></symbol>
<symbol id="q-pot" viewBox="0 0 24 24"><path d="M4.5 10h15v6a4.5 4.5 0 0 1-4.5 4.5H9A4.5 4.5 0 0 1 4.5 16zM2.5 12h2M19.5 12h2M9 3.5c-.8 1 .8 2 0 3M12 3c-.8 1 .8 2 0 3M15 3.5c-.8 1 .8 2 0 3"/></symbol>
<symbol id="q-rain" viewBox="0 0 24 24"><path d="M7 15.5a4 4 0 0 1-.4-8A5.5 5.5 0 0 1 17.2 8a3.8 3.8 0 0 1-.2 7.5z"/><path d="M8.5 18.5l-.8 2M12.5 18.5l-.8 2M16.5 18.5l-.8 2"/></symbol>
<symbol id="q-chat" viewBox="0 0 24 24"><path d="M4 5.5h11a2 2 0 0 1 2 2V13a2 2 0 0 1-2 2H9l-4 3.5V15H4a2 2 0 0 1-2-2V7.5a2 2 0 0 1 2-2z"/><path d="M17 9h3a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-1v2.5L16 18h-2"/></symbol>
<symbol id="q-heart" viewBox="0 0 24 24"><path d="M12 20s-7.5-4.6-7.5-10A4.3 4.3 0 0 1 12 7.5 4.3 4.3 0 0 1 19.5 10c0 5.4-7.5 10-7.5 10z"/></symbol>
<symbol id="q-family" viewBox="0 0 24 24"><circle cx="8" cy="7" r="2.8"/><circle cx="16.5" cy="8" r="2.3"/><path d="M3 20v-1.5A5 5 0 0 1 8 13.5a5 5 0 0 1 5 5V20M13.5 14.2a4.2 4.2 0 0 1 7 3.1V20"/></symbol>
<symbol id="q-bag" viewBox="0 0 24 24"><rect x="3.5" y="8" width="17" height="12.5" rx="3"/><path d="M8.5 8V6a3.5 3.5 0 0 1 7 0v2M3.5 13h17M11 13v2h2v-2"/></symbol>
<symbol id="q-cal" viewBox="0 0 24 24"><rect x="3.5" y="5" width="17" height="15.5" rx="3"/><path d="M3.5 10h17M8 3v4M16 3v4M14 15.2l1.4 1.4 2.6-2.6"/></symbol>
<symbol id="q-camera" viewBox="0 0 24 24"><path d="M4.5 7.5h3l1.5-2.5h6l1.5 2.5h3a2 2 0 0 1 2 2V18a2 2 0 0 1-2 2h-15a2 2 0 0 1-2-2V9.5a2 2 0 0 1 2-2z"/><circle cx="12" cy="13.5" r="3.5"/></symbol>
<symbol id="q-baby" viewBox="0 0 24 24"><circle cx="12" cy="12.5" r="8.5"/><path d="M9.2 11.2h.01M14.8 11.2h.01M10 16a2.6 2.6 0 0 1 4 0M12 4c-1.2 0-1.6 1.2-.8 2"/></symbol>
</svg>
<div id="scroll">
<header class="bar" id="bar">
<button class="back" id="back" aria-label="返回"><svg class="ic"><use href="#i-back" xlink:href="#i-back"/></svg></button>
<span class="t">孕期专题</span>
</header>
<!-- ① 开始 -->
<main class="view" id="vStart">
<section class="hero">
<i class="o1"></i><i class="o2"></i>
<span class="eb">孕期趣味测试 · MAMA TYPE</span>
<h1>测一测<br>你是<mark>什么样</mark>的妈妈?</h1>
<div class="meta">
<span><svg class="ic"><use href="#i-list" xlink:href="#i-list"/></svg><b class="num">16</b>题 · 约<b class="num">2</b>分钟</span>
<span><svg class="ic"><use href="#i-lock" xlink:href="#i-lock"/></svg>只在本机算,不上传</span>
<span id="tested" hidden><svg class="ic"><use href="#q-heart" xlink:href="#q-heart"/></svg>已有<b class="num" id="testedN"></b>位妈妈测过</span>
</div>
<img class="pic" src="img/hero.webp" alt="孕妈拿着小测试卡片微笑">
</section>
<div class="wrap">
<section class="types fade">
<div class="sh2"><i>4 TYPES</i><b>4 种妈妈,你是哪一种?</b></div>
<div class="tgrid" id="tgrid"></div>
</section>
<div class="startbox fade">
<button class="btn pri" id="startBtn">开始测试<svg class="ic"><use href="#i-arrow" xlink:href="#i-arrow"/></svg></button>
<p class="note">没有对错,凭第一感觉选就好</p>
</div>
</div>
</main>
<!-- ② 答题 -->
<main class="view wrap" id="vQuiz">
<div class="qtop">
<button id="prevBtn"><svg class="ic"><use href="#i-back" xlink:href="#i-back"/></svg>上一题</button>
<span class="no num"><b id="qNo">1</b> / <span id="qTotal">16</span></span>
</div>
<div class="feet" id="feet" aria-hidden="true"></div>
<div class="stage" id="stage">
<div class="qcard">
<div class="hd">
<span class="qi"><svg class="ic"><use id="qIc" href="#q-test" xlink:href="#q-test"/></svg></span>
<span class="cat" id="qCat"></span>
</div>
<h2 id="qTitle"></h2>
</div>
<div class="opts" id="qOpts"></div>
</div>
<p class="qtip">选完自动进入下一题</p>
</main>
<!-- ③ 结果 -->
<main class="view wrap" id="vResult">
<article class="rcard" id="rCard">
<i class="o1"></i><i class="o2"></i>
<div class="top"><b>我的妈妈类型卡</b><span id="rLast"></span></div>
<div class="ava"><img id="rImg" src="" alt=""></div>
<p class="you">你是</p>
<h1><mark id="rName"></mark></h1>
<p class="slo" id="rLine"></p>
<div class="rtags" id="rTags"></div>
<div class="dims">
<svg id="rRadar" viewBox="-16 -2 168 146" role="img" aria-label="4 个维度占比雷达图"></svg>
<div class="dl" id="rDims"></div>
</div>
<p class="brand">兜爸心选 · 孕期专题 · 测一测你是什么样的妈妈</p>
</article>
<div class="racts">
<button class="btn pri" id="saveBtn"><svg class="ic"><use href="#i-down" xlink:href="#i-down"/></svg>保存结果卡</button>
<button class="btn sec" id="shareBtn"><svg class="ic"><use href="#i-copy" xlink:href="#i-copy"/></svg>写给未来宝宝</button>
</div>
<section class="blk fade">
<div class="sh2"><i>01</i><b>你是这样的妈妈</b></div>
<div class="read" id="rRead"></div>
</section>
<section class="blk fade">
<div class="sh2"><i>02</i><b>给你的小建议</b></div>
<div class="tips" id="rTips"></div>
</section>
<section class="blk fade">
<div class="sh2"><i>03</i><b>和你最搭的队友</b></div>
<div class="mate" id="rMate"></div>
</section>
<div id="tools" class="fade"></div>
<button class="btn sec again" id="againBtn"><svg class="ic"><use href="#i-refresh" xlink:href="#i-refresh"/></svg>重新测试</button>
</main>
<p class="foot">趣味测试,仅供娱乐;身体相关问题以产检医生意见为准</p>
</div>
<div class="mask" id="mask">
<img id="maskImg" alt="我的妈妈类型卡">
<p><svg class="ic"><use href="#i-hand" xlink:href="#i-hand"/></svg>长按图片,保存到相册</p>
<div class="row"><a id="dlBtn" download="妈妈类型卡.png" hidden>下载图片</a><button id="maskClose">关闭</button></div>
</div>
<div class="toast" id="toast"></div>
<script src="../_shared/tools.js"></script>
<script>
(function () {
'use strict';
var $ = function (s) { return document.querySelector(s); };
var sc = $('#scroll');
var KEY = 'mmbox.ceshi.v3';
var TESTED_COUNT = 0; /* 「已有 N 位妈妈测过」:只有接上真实统计后才填,0 = 不显示(不造数字) */
var XL = 'http://www.w3.org/1999/xlink';
function useRef(el, id) { el.setAttribute('href', '#' + id); el.setAttributeNS(XL, 'xlink:href', '#' + id); }
function esc(s) { return String(s).replace(/[&<>"]/g, function (c) { return { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;' }[c]; }); }
var openid = (function () {
var m = (location.hash + '&' + location.search).match(/[#?&]openid=([^&#]+)/);
return m ? decodeURIComponent(m[1]) : '';
})();
/* 返回:从首页点进来就 back;直接打开(分享 / 刷新)就回同目录的首页,身份 hash 原样带回 */
$('#back').addEventListener('click', function () {
if (document.referrer && document.referrer.indexOf(location.host) >= 0 && history.length > 1) history.back();
else location.href = '../../' + location.search + location.hash;
});
sc.addEventListener('scroll', function () { $('#bar').classList.toggle('sh', sc.scrollTop > 4); }, { passive: true });
/* ================= 4 个维度 = 4 种类型 =================
* ORDER 顺序 = 雷达图顺时针(上/右/下/左)。
* dim:维度名;tools:按类型推荐的工具(理由贴合性格,≤18 字);mate:最搭的队友类型。 */
var TYPES = {
nuan: { name: '温柔守护型', dim: '细心守护', ax: '守护', img: 'img/nuan.webp', alt: '妈妈温柔地抱着宝宝',
line: '你的爱细腻又安稳,是宝宝最软的依靠', tags: ['共情力强', '细心周到', '安全感满满'],
desc: '你把宝宝的每一点动静都放在心上,爱得细腻,也容易替他多操一份心。',
side: '那份柔软一直都在。',
tips: ['担心的事随手记下来,产检时一次问清,别一个人反复琢磨。', '胎动、血压这些交给工具记,看得见数据,心里更踏实。'],
low: '偶尔停下来摸摸肚子、跟宝宝说说话,这份连接很珍贵。',
mate: 'song', mateWhy: '你替宝宝想得多,TA 帮你把担心放一放,一起把日子过得轻松些。',
tools: [
{ id: 'taidong', why: '每天数一数,宝宝动静看得见' },
{ id: 'taierguzhong', why: '对照 B 超看宝宝长得好不好' },
{ id: 'yun', why: '血压记下来,心里更有底' } ] },
xue: { name: '理性计划型', dim: '规划研究', ax: '规划', img: 'img/xue.webp', alt: '孕妈认真看书做笔记',
line: '知识是你的底气,每一步都提前想好', tags: ['计划周全', '会甄别信息', '遇事冷静'],
desc: '遇到事情你先查、先记、先排计划,什么都要心里有数才安心。',
side: '遇事先想清楚,是你的底气。',
tips: ['网上说法真假混杂,吓人的先打个问号,以产检医生意见为准。', '计划赶不上变化很正常,给自己和宝宝都留一点弹性。'],
low: '关键节点提前排一排:产检、待产包、入院路线,到时就不慌。',
mate: 're', mateWhy: '你负责把计划排好,TA 负责把气氛带热,全家都愿意跟着你行动。',
tools: [
{ id: 'chanjianrili', why: '产检时间一次排好,提前准备' },
{ id: 'yunqitizhong', why: '体重画成曲线,涨多涨少一目了然' },
{ id: 'yunqixuetang', why: '按餐记血糖,数据控最安心' } ] },
song: { name: '松弛自在型', dim: '松弛乐观', ax: '松弛', img: 'img/song.webp', alt: '孕妈靠在软垫上悠闲喝茶',
line: '情绪稳定心态好,好心情就是最好的胎教', tags: ['情绪稳定', '抓大放小', '快乐能量'],
desc: '你抓大放小、不内耗,身边的人跟你待在一起都会放松下来。',
side: '该放下时你也放得下。',
tips: ['松弛也别错过关键产检:唐筛、大排畸、糖耐提前约好。', '拿不准能不能吃的,花 10 秒查一下,再放心大口吃。'],
low: '给自己留点「什么都不做」的时间,妈妈放松,宝宝也舒服。',
mate: 'nuan', mateWhy: '你心大不内耗,TA 细心会提醒,大事小事都不落下。',
tools: [
{ id: 'yunqinengbuchi', why: '想吃先查 10 秒,吃得更放心' },
{ id: 'daichanqingdan', why: '照清单买齐必需品,不费心' },
{ id: 'chanjianrili', why: '关键产检到点提醒,不怕忘' } ] },
re: { name: '元气分享型', dim: '分享连接', ax: '分享', img: 'img/re.webp', alt: '孕妈和朋友们开心聊天',
line: '热情开朗爱连接,总有人陪你期待宝宝', tags: ['社交满分', '乐于分享', '行动力强'],
desc: '开心和担心你都愿意说出来,身边总围着一群陪你期待宝宝的人。',
side: '有人陪着,你会更有力量。',
tips: ['群里的经验只作参考,涉及用药和检查,以医生意见为准。', '孕肚照、胎动瞬间都存下来,以后都是全家的宝贵回忆。'],
low: '心里的事别憋着,说给老公或闺蜜听,有人分担会轻松很多。',
mate: 'xue', mateWhy: '你消息多、朋友多,TA 帮你把信息筛一筛,靠谱的留下来。',
tools: [
{ id: 'yundujinian', why: '孕肚照、B 超照存一起,随时分享' },
{ id: 'taidong', why: '叫上老公一起数,感受宝宝在动' },
{ id: 'daichanqingdan', why: '清单发给家人,分工一起准备' } ] }
};
var ORDER = ['nuan', 'xue', 'song', 're'];
/* ================= 16 道题 · 计分表 =================
* 每个选项 = [维度, 文案],选中即该维度 +1,共 16 分;选项顺序已人工打散。
* c:题目所属场景(解读里引用);s:场景短语(「X 时,你选了…」);ic:题目场景图标。 */
var QS = [
{ c: '情绪时刻', ic: 'q-test', s: '看到验孕棒两道杠', q: '验孕棒出现两道杠的那一刻,你的第一反应是?', o: [
['nuan', '手不自觉放到肚子上,眼眶有点热'], ['xue', '马上算预产期,开始列待办清单'], ['re', '立刻拍照发给老公'], ['song', '先淡定,去医院确认了再说'] ] },
{ c: '身体与产检', ic: 'q-board', s: '大排畸前一晚', q: '明天要做大排畸了,今晚的你?', o: [
['xue', '把想问医生的问题一条条写下来'], ['song', '照常追剧,早点睡就好'], ['nuan', '有点睡不着,一遍遍摸肚子'], ['re', '去孕妈群看看大家都怎么准备'] ] },
{ c: '身体与产检', ic: 'q-wait', s: '产检排长队', q: '产检排队等了一个多小时,你在?', o: [
['re', '和旁边的孕妈聊成了朋友'], ['xue', '翻看上次报告,对比各项数值'], ['nuan', '悄悄跟宝宝说「快轮到我们啦」'], ['song', '刷刷手机打个盹,不着急'] ] },
{ c: '身体与产检', ic: 'q-moon', s: '半夜宝宝拳打脚踢', q: '半夜宝宝在肚子里拳打脚踢,你会?', o: [
['song', '翻个身,跟着节奏又睡着了'], ['nuan', '轻轻拍拍肚子:妈妈在呢'], ['re', '推醒老公:快来摸,他在踢'], ['xue', '看看时间,顺手记一笔胎动'] ] },
{ c: '身体与产检', ic: 'q-scale', s: '体重涨得有点快', q: '这个月体重涨得有点快,你会?', o: [
['xue', '开始每天称重,画条曲线看看'], ['re', '拉上姐妹一起饭后散步'], ['song', '下顿少吃点主食,不焦虑'], ['nuan', '担心影响宝宝,赶紧问问医生'] ] },
{ c: '吃喝日常', ic: 'q-phone', s: '刷到「孕期千万别吃」', q: '刷到一条「孕期千万别吃 XX」,你会?', o: [
['nuan', '宁可信其有,先不吃了'], ['re', '转给姐妹:你们看到这个没'], ['xue', '先查权威说法,再决定'], ['song', '适量就好,不太往心里去'] ] },
{ c: '吃喝日常', ic: 'q-bowl', s: '半夜嘴馋', q: '半夜突然特别想吃酸辣粉,你会?', o: [
['song', '想吃就吃,开心最重要'], ['xue', '先查查孕妇能不能吃、吃多少'], ['nuan', '忍一忍,明天自己做份干净的'], ['re', '发条朋友圈:谁懂这种馋'] ] },
{ c: '家人相处', ic: 'q-pot', s: '婆婆端来补汤', q: '婆婆端来一大锅补汤,你会?', o: [
['re', '拍照发群:被宠到了'], ['nuan', '笑着喝两口,谢谢婆婆的心意'], ['song', '喝一碗,剩下全家分着喝'], ['xue', '先问问汤里放了什么药材'] ] },
{ c: '情绪时刻', ic: 'q-rain', s: '没来由想哭', q: '没来由地想哭的时候,你会?', o: [
['xue', '想到是激素在作怪,就释然了'], ['nuan', '抱抱自己,允许情绪来一会儿'], ['re', '打给闺蜜,聊完就好了'], ['song', '睡一觉,醒来又是好心情'] ] },
{ c: '情绪时刻', ic: 'q-chat', s: '被问「怀孕辛苦吗」', q: '朋友问你「怀孕辛苦吗」,你的回答是?', o: [
['song', '还好呀,能吃能睡挺快乐'], ['re', '辛苦!来,听我细细说'], ['nuan', '辛苦,但每次胎动都觉得值'], ['xue', '还行,每个阶段我都提前了解过'] ] },
{ c: '家人相处', ic: 'q-heart', s: '老公想多参与', q: '老公说「我也想多参与孕期」,你会让他?', o: [
['nuan', '每晚给宝宝讲个睡前故事'], ['xue', '学会看懂产检报告'], ['re', '陪你去上孕妈课,认识新朋友'], ['song', '负责每天逗你开心就够了'] ] },
{ c: '家人相处', ic: 'q-family', s: '家里带娃意见不一', q: '家里人对以后怎么带娃意见不一,你会?', o: [
['song', '大方向对就行,细节不纠结'], ['re', '全家开个小会,摊开来聊'], ['xue', '找资料,用科学依据说话'], ['nuan', '先照顾大家情绪,再慢慢沟通'] ] },
{ c: '待产准备', ic: 'q-bag', s: '收拾待产包', q: '准备待产包,你的风格更像?', o: [
['xue', '按清单逐项打勾,一样不落'], ['re', '拉闺蜜一起逛,顺手分享心得'], ['nuan', '小衣服洗好晒好,叠得整整齐齐'], ['song', '买齐必需品,缺啥再补'] ] },
{ c: '待产准备', ic: 'q-cal', s: '离预产期还剩一个月', q: '离预产期还剩一个月,你在?', o: [
['re', '和同月孕妈约好互报喜讯'], ['song', '该吃吃该睡睡,等着发动'], ['xue', '把去医院的路线和流程走一遍'], ['nuan', '每天跟宝宝说:慢慢来,不着急'] ] },
{ c: '想象宝宝', ic: 'q-camera', s: '想象宝宝第一张照片', q: '想象宝宝的第一张照片,你希望是?', o: [
['nuan', '小手紧紧攥着你的手指'], ['song', '宝宝睡得四仰八叉'], ['xue', '配上身长体重的出生卡'], ['re', '全家围着宝宝笑成一团'] ] },
{ c: '想象宝宝', ic: 'q-baby', s: '想象宝宝哭个不停', q: '想象宝宝第一次哭个不停,你会?', o: [
['xue', '逐项排查:饿了、尿了还是困了'], ['nuan', '抱在怀里,轻轻哼歌'], ['song', '先稳住自己,深呼吸'], ['re', '视频问问有经验的妈妈'] ] }
];
$('#qTotal').textContent = QS.length;
/* 开始页:4 种类型小卡 + 测过人数(仅真实数据) */
$('#tgrid').innerHTML = ORDER.map(function (k) {
var t = TYPES[k];
return '<div class="tcard"><img src="' + t.img + '" alt=""><span><b>' + t.name + '</b><small>' + t.tags[0] + '</small></span></div>';
}).join('');
if (TESTED_COUNT > 0) { $('#testedN').textContent = TESTED_COUNT.toLocaleString('zh-CN'); $('#tested').hidden = false; }
/* 进场动画:按顺序 60ms 错开 */
var views = { start: $('#vStart'), quiz: $('#vQuiz'), result: $('#vResult') };
var io = 'IntersectionObserver' in window ? new IntersectionObserver(function (es) {
var n = 0;
es.forEach(function (e) {
if (!e.isIntersecting) return;
var el = e.target; io.unobserve(el);
setTimeout(function () { el.classList.add('in'); }, 60 * n++);
});
}, { root: sc, threshold: .08 }) : null;
/* 11-03 用户:「重新测试后退回首页,再进来还是结果页」→ 记住最后停在哪(开始 / 第几题 / 结果),再进来回到那里 */
function pos(v) {
if (v) pos.v = v;
try { localStorage.setItem(KEY + '.pos', JSON.stringify({ v: pos.v, cur: cur, ans: ans })); } catch (e) {}
}
function resume() {
var p = null; try { p = JSON.parse(localStorage.getItem(KEY + '.pos') || 'null'); } catch (e) {}
if (!p) return false; /* 旧用户没有记录:照原来的(有结果看结果) */
if (p.v === 'start') { show('start'); return true; }
if (p.v === 'quiz' && Array.isArray(p.ans)) { cur = Math.max(0, Math.min(+p.cur || 0, QS.length - 1)); ans = p.ans.slice(0, QS.length); paint(); show('quiz'); return true; }
return false;
}
function show(name) {
pos(name);
Object.keys(views).forEach(function (k) { views[k].classList.toggle('on', k === name); });
sc.scrollTop = 0;
[].forEach.call(views[name].querySelectorAll('.fade'), function (el) {
el.classList.remove('in');
if (io) { io.unobserve(el); io.observe(el); } else el.classList.add('in');
});
}
/* ================= 答题 ================= */
var cur = 0, ans = [], busy = false;
var stage = $('#stage');
$('#feet').innerHTML = QS.map(function () { return '<svg viewBox="0 0 24 24"><use href="#i-foot" xlink:href="#i-foot"/></svg>'; }).join('');
var feet = document.querySelectorAll('#feet svg');
function paint() {
var q = QS[cur];
$('#qNo').textContent = cur + 1;
[].forEach.call(feet, function (f, i) { f.setAttribute('class', i < cur ? 'done' : i === cur ? 'cur' : ''); });
useRef($('#qIc'), q.ic);
$('#qCat').textContent = q.c;
$('#qTitle').textContent = q.q;
$('#qOpts').innerHTML = q.o.map(function (o, i) {
return '<button class="opt' + (ans[cur] === i ? ' sel' : '') + '" data-i="' + i + '"><span class="l">' + 'ABCD'[i] + '</span><span>' + esc(o[1]) +
'</span><span class="ck"><svg class="ic"><use href="#i-check" xlink:href="#i-check"/></svg></span></button>';
}).join('');
$('#prevBtn').disabled = cur === 0;
if (pos.v === 'quiz') pos();
}
/* 左右滑动:前进 → 当前向左滑出、新题从右滑入;上一题反过来 */
function swap(dir, after) {
busy = true;
stage.classList.add(dir > 0 ? 'outL' : 'outR');
setTimeout(function () {
after();
stage.classList.remove('outL', 'outR');
stage.classList.add(dir > 0 ? 'inR' : 'inL');
void stage.offsetWidth;
stage.classList.remove('inR', 'inL');
setTimeout(function () { busy = false; }, 220);
}, 220);
}
$('#qOpts').addEventListener('click', function (e) {
var b = e.target.closest('.opt'); if (!b || busy) return;
busy = true;
ans[cur] = +b.dataset.i;
[].forEach.call(document.querySelectorAll('#qOpts .opt'), function (x) { x.classList.toggle('sel', x === b); });
setTimeout(function () {
if (cur < QS.length - 1) swap(1, function () { cur++; paint(); });
else { busy = false; finish(); }
}, 380);
});
$('#prevBtn').addEventListener('click', function () {
if (busy || cur === 0) return;
swap(-1, function () { cur--; paint(); });
});
function startQuiz() {
cur = 0; ans = []; busy = false;
stage.classList.remove('outL', 'outR', 'inL', 'inR');
paint();
show('quiz');
}
$('#startBtn').addEventListener('click', startQuiz);
$('#againBtn').addEventListener('click', startQuiz);
/* ================= 计分 ================= */
function score(answers) {
var s = { nuan: 0, xue: 0, song: 0, re: 0 };
answers.forEach(function (i, qi) { s[QS[qi].o[i][0]]++; });
/* 最高分为主类型;并列时取「最近一次选过」的那个(越靠后的题越接近真实状态) */
var max = Math.max.apply(null, ORDER.map(function (k) { return s[k]; }));
var tied = ORDER.filter(function (k) { return s[k] === max; });
var top = tied[0];
if (tied.length > 1) for (var qi = answers.length - 1; qi >= 0; qi--) {
var t = QS[qi].o[answers[qi]][0];
if (tied.indexOf(t) >= 0) { top = t; break; }
}
return { s: s, top: top };
}
function pcts(s, top) {
var total = 0; ORDER.forEach(function (k) { total += s[k]; }); total = total || 1;
var p = {}; ORDER.forEach(function (k) { p[k] = Math.round(s[k] / total * 100); });
var diff = 100; ORDER.forEach(function (k) { diff -= p[k]; });
p[top] += diff; /* 四舍五入补差,合计 100% */
return p;
}
function finish() {
var r = score(ans);
var rec = { type: r.top, scores: r.s, ans: ans.slice(), at: Date.now() };
try { localStorage.setItem(KEY, JSON.stringify(rec)); } catch (e) {}
render(rec, false);
}
/* ================= 解读:引用作答 ================= */
function reading(rec, p) {
var t = TYPES[rec.type], a = rec.ans;
var picks = function (k) { var r = []; a.forEach(function (i, qi) { if (QS[qi].o[i][0] === k) r.push(qi); }); return r; };
var mine = picks(rec.type);
/* 主类型最集中的场景 */
var byCat = {};
QS.forEach(function (q, qi) { var c = byCat[q.c] || (byCat[q.c] = { n: 0, hit: [] }); c.n++; if (QS[qi].o[a[qi]][0] === rec.type) c.hit.push(qi); });
var best = null;
Object.keys(byCat).forEach(function (c) {
var x = byCat[c]; if (!x.hit.length) return;
var sc_ = x.hit.length / x.n + x.hit.length * .01;
if (!best || sc_ > best.sc) best = { c: c, sc: sc_, x: x };
});
var ex = QS[best.x.hit[best.x.hit.length - 1]];
var exOpt = ex.o[a[QS.indexOf(ex)]][1];
var html = '<p>16 道题里,你有 <b class="num">' + mine.length + '</b> 次选了「' + t.dim + '」的答案。' + esc(t.desc) + '</p>';
html += '<p>' + (best.x.hit.length === best.x.n ? '在「' + best.c + '」的 ' + best.x.n + ' 道题里,你每次都这样选' : '尤其在「' + best.c + '」的题里,你 ' + best.x.n + ' 次有 ' + best.x.hit.length + ' 次这样选') +
':比如' + ex.s + ',你选了<q>' + esc(exOpt) + '</q>。</p>';
/* 第二维度 */
var rest = ORDER.filter(function (k) { return k !== rec.type; }).sort(function (x, y) { return rec.scores[y] - rec.scores[x]; });
var sec = rest[0];
if (rec.scores[sec] > 0) {
var sp = picks(sec), sq = QS[sp[sp.length - 1]];
html += '<p>你的另一面是「' + TYPES[sec].dim + '」(<span class="num">' + p[sec] + '%</span>):' + sq.s + '时,你选了<q>' + esc(sq.o[a[QS.indexOf(sq)]][1]) + '</q>,' + TYPES[sec].side + '</p>';
} else {
html += '<p>16 道题你全选了同一类,是非常纯粹的' + t.name + '妈妈。</p>';
}
return html;
}
function tips(rec, p) {
var t = TYPES[rec.type];
var low = ORDER.filter(function (k) { return k !== rec.type; }).sort(function (x, y) { return rec.scores[x] - rec.scores[y]; })[0];
return t.tips.concat(['你在「' + TYPES[low].dim + '」上只占 ' + p[low] + '%,' + TYPES[low].low]);
}
/* ================= 雷达图(SVG 手写,单系列) ================= */
function radarPts(p, cx, cy, R, M) {
/* 上、右、下、左 */
var d = [[0, -1], [1, 0], [0, 1], [-1, 0]];
return ORDER.map(function (k, i) { var r = Math.max(p[k] / M, .06) * R; return [cx + d[i][0] * r, cy + d[i][1] * r]; });
}
function radarScale(p) { var m = 0; ORDER.forEach(function (k) { m = Math.max(m, p[k]); }); return Math.max(50, Math.ceil(m / 10) * 10); }
function radarSVG(p, top) {
var cx = 68, cy = 68, R = 44, M = radarScale(p), g = '';
[1 / 3, 2 / 3, 1].forEach(function (f) {
var r = R * f; g += '<polygon points="' + [cx, cy - r, cx + r, cy, cx, cy + r, cx - r, cy].join(',') + '" fill="none" stroke="#E4DDFD" stroke-width="1"/>';
});
g += '<path d="M' + cx + ' ' + (cy - R) + 'V' + (cy + R) + 'M' + (cx - R) + ' ' + cy + 'H' + (cx + R) + '" stroke="#E4DDFD" stroke-width="1"/>';
var pts = radarPts(p, cx, cy, R, M);
g += '<polygon points="' + pts.map(function (x) { return x.join(','); }).join(' ') + '" fill="rgba(124,92,252,.18)" stroke="#7C5CFC" stroke-width="2" stroke-linejoin="round"/>';
pts.forEach(function (x, i) { g += '<circle cx="' + x[0] + '" cy="' + x[1] + '" r="' + (ORDER[i] === top ? 4.5 : 3.2) + '" fill="#7C5CFC" stroke="#fff" stroke-width="1.5"/>'; });
var L = [[cx, 12, 'middle'], [cx + R + 6, cy + 4, 'start'], [cx, cy + R + 18, 'middle'], [cx - R - 6, cy + 4, 'end']];
ORDER.forEach(function (k, i) {
g += '<text x="' + L[i][0] + '" y="' + L[i][1] + '" text-anchor="' + L[i][2] + '" font-size="11" font-weight="' + (k === top ? 800 : 500) + '" fill="' + (k === top ? '#7C5CFC' : '#86909C') + '">' + TYPES[k].ax + '</text>';
});
return g;
}
/* ================= 渲染结果 ================= */
var curRec = null, curP = null, wk = 0;
function render(rec, fromCache) {
var t = TYPES[rec.type], p = pcts(rec.scores, rec.type);
curRec = rec; curP = p;
$('#rImg').src = t.img; $('#rImg').alt = t.alt;
$('#rName').textContent = t.name + '妈妈';
$('#rLine').textContent = t.line;
var d = new Date(rec.at || Date.now());
$('#rLast').textContent = (fromCache ? '上次测试 · ' : '') + (d.getMonth() + 1) + '月' + d.getDate() + '日';
$('#rTags').innerHTML = t.tags.map(function (a) { return '<span>' + esc(a) + '</span>'; }).join('');
$('#rRadar').innerHTML = radarSVG(p, rec.type);
var sorted = ORDER.slice().sort(function (x, y) { return (y === rec.type) - (x === rec.type) || p[y] - p[x]; });
$('#rDims').innerHTML = sorted.map(function (k) {
return '<div class="dr' + (k === rec.type ? ' me' : '') + '"><span>' + TYPES[k].dim + '</span><span class="p num">' + p[k] + '%</span><span class="tr"><i data-w="' + p[k] + '"></i></span></div>';
}).join('');
$('#rRead').innerHTML = reading(rec, p);
$('#rTips').innerHTML = tips(rec, p).map(function (x, i) { return '<div class="tp"><span class="n">' + (i + 1) + '</span><p>' + esc(x) + '</p></div>'; }).join('');
var m = TYPES[t.mate];
$('#rMate').innerHTML = '<img src="' + m.img + '" alt=""><span><small>队友(老公 / 家人)是这一型最合拍</small><b>' + m.name + '</b><p>' + esc(t.mateWhy) + '</p></span>';
renderTools();
show('result');
setTimeout(function () { [].forEach.call(document.querySelectorAll('#rDims i'), function (b) { b.style.width = b.dataset.w + '%'; }); }, 250);
}
function renderTools() {
if (!curRec || !window.TopicTools) return;
var el = $('#tools'); el.className = 'fade in';
TopicTools.render(el, TYPES[curRec.type].tools, { title: TYPES[curRec.type].name + '妈妈用得上', color: '#7C5CFC', bg: '#F1EDFF', wk: wk });
}
/* 孕周:只用来给推荐工具打「孕N周开放」标签 */
if (openid) {
fetch('/api/mp/public/mama-box/pregnancy?openid=' + encodeURIComponent(openid))
.then(function (r) { return r.ok ? r.json() : null; })
.then(function (j) {
var p = j && j.code === 200 && j.result;
if (p && !p.postpartum && !p.empty && p.week != null) { wk = +p.week || 0; renderTools(); }
}).catch(function () {});
}
/* ================= 分享:复制文案 ================= */
var tt;
function toast(msg) {
var el = $('#toast'); el.textContent = msg; el.classList.add('on');
clearTimeout(tt); tt = setTimeout(function () { el.classList.remove('on'); }, 2400);
}
function copy(text) {
function legacy() { return new Promise(function (ok, no) {
var ta = document.createElement('textarea');
ta.value = text; ta.setAttribute('readonly', ''); ta.style.cssText = 'position:fixed;top:-999px;opacity:0';
document.body.appendChild(ta); ta.select();
var r = false; try { r = document.execCommand('copy'); } catch (e) {}
document.body.removeChild(ta);
r ? ok() : no();
}); }
if (navigator.clipboard && window.isSecureContext) return navigator.clipboard.writeText(text).catch(legacy);
return legacy();
}
$('#shareBtn').addEventListener('click', function () {
if (!curRec) return;
var t = TYPES[curRec.type];
var BABY = {
nuan: '等你来了,妈妈会把你抱得稳稳的,你哭的时候、怕的时候,妈妈都在。',
xue: '你要用的东西、要打的疫苗,妈妈都提前排好了,你只管安心长大。',
song: '妈妈不求你样样第一,只希望你健康、快乐,慢慢长大也没关系。',
re: '好多人都在等你呢,等你来了,妈妈带你去看这个热热闹闹的世界。'
};
var text = '宝宝,妈妈今天测出来是「' + t.name + '妈妈」——' + t.line + '。' + BABY[curRec.type] + '我们很快就见面啦。';
copy(text).then(function () { toast('已复制,存进备忘录,等宝宝长大念给宝宝听'); }, function () { toast('点「保存结果卡」,把这一刻存下来吧'); });
});
/* ================= 保存结果卡:canvas 画图 → <img> 长按保存 ================= */
var FONT = '-apple-system,BlinkMacSystemFont,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif';
function rr(ctx, x, y, w, h, r) {
ctx.beginPath(); ctx.moveTo(x + r, y); ctx.arcTo(x + w, y, x + w, y + h, r); ctx.arcTo(x + w, y + h, x, y + h, r);
ctx.arcTo(x, y + h, x, y, r); ctx.arcTo(x, y, x + w, y, r); ctx.closePath();
}
function loadImg(src) { return new Promise(function (ok, no) { var im = new Image(); im.onload = function () { ok(im); }; im.onerror = no; im.src = src; }); }
function drawCard(im) {
var t = TYPES[curRec.type], p = curP, W = 750, H = 1200;
var cv = document.createElement('canvas'); cv.width = W; cv.height = H;
var ctx = cv.getContext('2d');
var g = ctx.createLinearGradient(0, 0, W * .3, H);
g.addColorStop(0, '#E9E2FF'); g.addColorStop(.45, '#F6F3FF'); g.addColorStop(1, '#FFFFFF');
ctx.fillStyle = g; ctx.fillRect(0, 0, W, H);
ctx.fillStyle = 'rgba(255,255,255,.55)'; ctx.beginPath(); ctx.arc(660, 90, 230, 0, 7); ctx.fill();
ctx.fillStyle = 'rgba(124,92,252,.06)'; ctx.beginPath(); ctx.arc(40, 470, 150, 0, 7); ctx.fill();
ctx.textAlign = 'center'; ctx.textBaseline = 'alphabetic';
/* 顶部胶囊 */
ctx.font = '700 24px ' + FONT;
var lb = '我的妈妈类型卡', lw = ctx.measureText(lb).width + 44;
ctx.fillStyle = '#fff'; rr(ctx, (W - lw) / 2, 52, lw, 48, 24); ctx.fill();
ctx.fillStyle = '#7C5CFC'; ctx.fillText(lb, W / 2, 84);
/* 插画 */
var S = 320, ix = (W - S) / 2, iy = 132;
ctx.save(); ctx.shadowColor = 'rgba(124,92,252,.18)'; ctx.shadowBlur = 36; ctx.shadowOffsetY = 12;
ctx.fillStyle = '#fff'; rr(ctx, ix - 10, iy - 10, S + 20, S + 20, 60); ctx.fill(); ctx.restore();
ctx.save(); rr(ctx, ix, iy, S, S, 52); ctx.clip();
var sw = im.naturalWidth, sh = im.naturalHeight, side = Math.min(sw, sh);
ctx.drawImage(im, (sw - side) / 2, (sh - side) * .3, side, side, ix, iy, S, S); ctx.restore();
/* 类型名 */
ctx.fillStyle = '#86909C'; ctx.font = '400 26px ' + FONT; ctx.fillText('你 是', W / 2, 520);
ctx.font = '800 60px ' + FONT;
var nm = t.name + '妈妈', nw = ctx.measureText(nm).width;
ctx.fillStyle = 'rgba(124,92,252,.20)'; ctx.fillRect((W - nw) / 2 - 4, 566, nw + 8, 24);
ctx.fillStyle = '#1F2329'; ctx.fillText(nm, W / 2, 588);
ctx.fillStyle = '#4E5969'; ctx.font = '400 28px ' + FONT; ctx.fillText(t.line, W / 2, 640);
/* 关键词 */
ctx.font = '700 26px ' + FONT;
var ws = t.tags.map(function (s) { return ctx.measureText(s).width + 44; }), gap = 16;
var tx = (W - ws.reduce(function (a, b) { return a + b; }, 0) - gap * 2) / 2;
t.tags.forEach(function (s, i) {
ctx.save(); ctx.shadowColor = 'rgba(124,92,252,.12)'; ctx.shadowBlur = 14; ctx.shadowOffsetY = 4;
ctx.fillStyle = '#fff'; rr(ctx, tx, 680, ws[i], 56, 28); ctx.fill(); ctx.restore();
ctx.fillStyle = '#7C5CFC'; ctx.fillText(s, tx + ws[i] / 2, 717); tx += ws[i] + gap;
});
/* 维度面板 */
ctx.fillStyle = 'rgba(255,255,255,.9)'; rr(ctx, 40, 776, 670, 300, 36); ctx.fill();
var cx = 205, cy = 926, R = 88, M = radarScale(p);
ctx.strokeStyle = '#E4DDFD'; ctx.lineWidth = 2;
[1 / 3, 2 / 3, 1].forEach(function (f) { var r = R * f; ctx.beginPath(); ctx.moveTo(cx, cy - r); ctx.lineTo(cx + r, cy); ctx.lineTo(cx, cy + r); ctx.lineTo(cx - r, cy); ctx.closePath(); ctx.stroke(); });
ctx.beginPath(); ctx.moveTo(cx, cy - R); ctx.lineTo(cx, cy + R); ctx.moveTo(cx - R, cy); ctx.lineTo(cx + R, cy); ctx.stroke();
var pts = radarPts(p, cx, cy, R, M);
ctx.beginPath(); pts.forEach(function (x, i) { i ? ctx.lineTo(x[0], x[1]) : ctx.moveTo(x[0], x[1]); }); ctx.closePath();
ctx.fillStyle = 'rgba(124,92,252,.18)'; ctx.fill(); ctx.strokeStyle = '#7C5CFC'; ctx.lineWidth = 4; ctx.lineJoin = 'round'; ctx.stroke();
pts.forEach(function (x, i) { ctx.beginPath(); ctx.arc(x[0], x[1], ORDER[i] === curRec.type ? 9 : 6.5, 0, 7); ctx.fillStyle = '#7C5CFC'; ctx.fill(); ctx.lineWidth = 3; ctx.strokeStyle = '#fff'; ctx.stroke(); });
var L = [[cx, cy - R - 16, 'center'], [cx + R + 12, cy + 8, 'left'], [cx, cy + R + 34, 'center'], [cx - R - 12, cy + 8, 'right']];
ORDER.forEach(function (k, i) {
ctx.textAlign = L[i][2]; ctx.font = (k === curRec.type ? '800' : '500') + ' 22px ' + FONT;
ctx.fillStyle = k === curRec.type ? '#7C5CFC' : '#86909C'; ctx.fillText(TYPES[k].ax, L[i][0], L[i][1]);
});
var sorted = ORDER.slice().sort(function (x, y) { return (y === curRec.type) - (x === curRec.type) || p[y] - p[x]; });
sorted.forEach(function (k, i) {
var y = 838 + i * 64, me = k === curRec.type;
ctx.textAlign = 'left'; ctx.font = (me ? '700' : '400') + ' 25px ' + FONT; ctx.fillStyle = me ? '#7C5CFC' : '#4E5969'; ctx.fillText(TYPES[k].dim, 388, y + 10);
ctx.textAlign = 'right'; ctx.font = '700 25px ' + FONT; ctx.fillStyle = me ? '#7C5CFC' : '#1F2329'; ctx.fillText(p[k] + '%', 674, y + 10);
ctx.fillStyle = '#EFEAFF'; rr(ctx, 388, y + 24, 286, 10, 5); ctx.fill();
ctx.fillStyle = me ? '#7C5CFC' : '#C7B9FE'; rr(ctx, 388, y + 24, Math.max(10, 286 * p[k] / 100), 10, 5); ctx.fill();
});
/* 底部 */
ctx.textAlign = 'center';
ctx.fillStyle = '#1F2329'; ctx.font = '700 26px ' + FONT; ctx.fillText('测一测你是什么样的妈妈?', W / 2, 1128);
ctx.fillStyle = '#86909C'; ctx.font = '400 21px ' + FONT; ctx.fillText('兜爸心选 · 孕期专题 · 趣味测试,仅供娱乐', W / 2, 1164);
return cv.toDataURL('image/png');
}
var isWx = /MicroMessenger/i.test(navigator.userAgent);
$('#saveBtn').addEventListener('click', function () {
if (!curRec) return;
toast('正在生成结果卡…');
loadImg(TYPES[curRec.type].img).then(function (im) {
var url = drawCard(im);
$('#maskImg').src = url;
var dl = $('#dlBtn'); dl.href = url; dl.hidden = isWx;
$('#toast').classList.remove('on');
$('#mask').classList.add('on');
}).catch(function () { toast('生成失败,截个图保存也可以'); });
});
$('#maskClose').addEventListener('click', function () { $('#mask').classList.remove('on'); });
$('#mask').addEventListener('click', function (e) { if (e.target === this) this.classList.remove('on'); });
/* 入口:有上次结果直接看结果,否则开始页 */
var saved = null;
try { saved = JSON.parse(localStorage.getItem(KEY) || 'null'); } catch (e) {}
if (resume()) ;
else if (saved && TYPES[saved.type] && saved.scores && saved.ans && saved.ans.length === QS.length) render(saved, true);
else show('start');
/* 禁止下拉回弹:固定外壳 + 容器滚动 + 到顶/到底时拦 touchmove */
var y0 = 0;
sc.addEventListener('touchstart', function (e) { y0 = e.touches[0].clientY; }, { passive: true });
sc.addEventListener('touchmove', function (e) {
var dy = e.touches[0].clientY - y0;
if ((sc.scrollTop <= 0 && dy > 0) || (sc.scrollTop + sc.clientHeight >= sc.scrollHeight - 1 && dy < 0)) e.preventDefault();
}, { passive: false });
document.addEventListener('touchmove', function (e) { if (!sc.contains(e.target)) e.preventDefault(); }, { passive: false });
})();
</script>
</body>
</html>