feat(首页): 3D 婴儿房入口三版——今天的动线与书架之间开一道空隙,房间铺在整页背后随滚动视差露出,「进去布置」按钮跳入并带 return_url (v26100112)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
111
js/app.js
111
js/app.js
@@ -3,7 +3,7 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
/* 页面版本号(YYMMDD+序号):显示在「关于兜爸心选」页底部;bump 时同步 head 注释与 ?v= */
|
||||
var VER = '26100111';
|
||||
var VER = '26100112';
|
||||
const $ = (s, c) => (c || document).querySelector(s);
|
||||
const $$ = (s, c) => Array.from((c || document).querySelectorAll(s));
|
||||
|
||||
@@ -3098,104 +3098,51 @@
|
||||
}, 2600);
|
||||
})();
|
||||
|
||||
/* ================= 3D 婴儿房 · 入口(2026-10-01 二版:走廊尽头的门)=================
|
||||
设计和取舍写在 index.html 的 #nursery 注释里。地址由「3D 婴儿房」会话(33d6c837)维护,对方目前不读任何参数。
|
||||
· 布置进度**只按孕周推演**(首页读不到房里真实摆了什么);syncPregnancy() 每次都会调 nurseryRender()。
|
||||
· 三态:preg(有真实孕周)/ born(产后,全布置好、门敞开)/ empty(没建档,空房间 + 引导填预产期)。 */
|
||||
/* ================= 3D 婴儿房 · 页面上的一道空隙(2026-10-01 三版)=================
|
||||
设计写在 index.html 的 #nursery 注释里。地址由「3D 婴儿房」会话(33d6c837)维护;
|
||||
带 return_url(首页净地址,不含 hash),对方返回按钮读到就跳回来。syncPregnancy() 每次都会调 nurseryRender()。 */
|
||||
const NURSERY_URL = 'https://beian3.douba.top/yef/';
|
||||
const NURSERY_ID = 'yef-nursery';
|
||||
const NY_STEPS = [
|
||||
{ w: 4, k: 'wall', n: '粉墙', t: '粉墙刷好了' },
|
||||
{ w: 12, k: 'curtain', n: '小窗帘', t: '小窗帘挂上了' },
|
||||
{ w: 16, k: 'rug', n: '软地毯', t: '软地毯铺好了' },
|
||||
{ w: 20, k: 'crib', n: '小床', t: '小床搬进来了' },
|
||||
{ w: 24, k: 'mobile', n: '床头风铃', t: '床头风铃挂上了' },
|
||||
{ w: 28, k: 'lamp', n: '小夜灯', t: '小夜灯装好了' },
|
||||
{ w: 32, k: 'bear', n: '玩偶熊', t: '玩偶熊住进来了' },
|
||||
{ w: 36, k: 'bag', n: '待产包', t: '待产包放在门口了' },
|
||||
{ w: 39, k: 'stars', n: '星星灯', t: '星星灯亮起来了' }
|
||||
];
|
||||
let nyLines = [], nyLineIdx = 0;
|
||||
function nurseryRender() {
|
||||
const sec = $('#nursery');
|
||||
if (!sec) return;
|
||||
if (!$('#nursery')) return;
|
||||
const nm = state.babyName || '宝宝';
|
||||
const mode = state.postpartum ? 'born' : (state.pregEmpty === false && state.week) ? 'preg' : 'empty';
|
||||
const wk = mode === 'born' ? 99 : mode === 'preg' ? state.week : 0;
|
||||
const done = NY_STEPS.filter(st => wk >= st.w);
|
||||
const last = done[done.length - 1], next = NY_STEPS[done.length];
|
||||
sec.classList.toggle('is-born', mode === 'born');
|
||||
$$('#nursery [data-k]').forEach((g) => {
|
||||
const k = g.getAttribute('data-k');
|
||||
g.classList.toggle('on', done.some(st => st.k === k));
|
||||
g.classList.toggle('new', mode === 'preg' && !!last && last.k === k && done.length > 1);
|
||||
});
|
||||
const dots = $('#nyDots');
|
||||
dots.innerHTML = NY_STEPS.map((st, i) =>
|
||||
'<i class="' + (i < done.length ? 'on' : '') + (mode === 'preg' && i === done.length - 1 ? ' cur' : '') + '"></i>').join('');
|
||||
dots.style.setProperty('--p', done.length ? ((done.length - 1) / (NY_STEPS.length - 1) * 100).toFixed(1) + '%' : '0%');
|
||||
$('#nySign').textContent = nm + '的房间';
|
||||
/* 入住倒计时:预产期 − 今天(按手机本地日期取整天) */
|
||||
$('#nyTitle').textContent = nm + '的房间';
|
||||
let days = null;
|
||||
if (mode === 'preg' && state.due) {
|
||||
if (!state.postpartum && state.pregEmpty === false && state.due) {
|
||||
const t = new Date(); t.setHours(0, 0, 0, 0);
|
||||
days = Math.round((state.due - t) / 864e5);
|
||||
}
|
||||
const cal = (top, num, unit, foot) => {
|
||||
$('#nyCalTop').textContent = top; $('#nyCalNum').textContent = num;
|
||||
$('#nyCalUnit').textContent = unit; $('#nyCalFoot').textContent = foot;
|
||||
};
|
||||
if (mode === 'born') cal('已入住', state.babyAgeDays == null ? '♥' : state.babyAgeDays, state.babyAgeDays == null ? '' : '天', '欢迎回家');
|
||||
else if (days != null && days > 0) cal('入住倒计时', days, '天', (state.due.getMonth() + 1) + '月' + state.due.getDate() + '日');
|
||||
else if (days != null) cal('入住倒计时', '0', '天', '随时入住');
|
||||
else cal('入住日', '?', '', '填预产期');
|
||||
if (mode === 'born') {
|
||||
$('#nyTitle').textContent = nm + '已经住进来啦';
|
||||
$('#nyProg').innerHTML = '房间布置好了 <b>9</b>/9,再给 TA 添点新东西吧';
|
||||
nyLines = ['这是我的房间!', '妈妈,再给我添件新玩具吧~'];
|
||||
} else if (mode === 'preg') {
|
||||
$('#nyTitle').textContent = '第 ' + wk + ' 周 · ' + (last ? last.t : '房间开始布置啦');
|
||||
$('#nyProg').innerHTML = '已布置 <b>' + done.length + '</b>/9' +
|
||||
(next ? ' · 下一件 ' + next.n : ' · 全都布置好啦');
|
||||
nyLines = ['妈妈,我的房间布置好了吗?'];
|
||||
if (last && done.length > 1) nyLines.push('听说' + last.n + '到了,我能看看吗?');
|
||||
if (next) nyLines.push('我还想要' + next.n + '~');
|
||||
if (days > 0) nyLines.push('再过 ' + days + ' 天,我就搬进来啦');
|
||||
} else {
|
||||
$('#nyTitle').textContent = nm + '的房间 · 还空着呢';
|
||||
$('#nyProg').innerHTML = '填好预产期,房间会跟着孕周一件件布置好';
|
||||
nyLines = ['妈妈,我的房间在哪呀?', '告诉我预产期,我就知道哪天搬进来啦'];
|
||||
}
|
||||
nyLineIdx = 0;
|
||||
$('#nyBubble').textContent = nyLines[0];
|
||||
$('#nySub').innerHTML = state.postpartum ? 'TA 已经住进来啦,再添点新东西吧'
|
||||
: days > 0 ? '还有 <em>' + days + '</em> 天入住 · 攒兜豆把它布置好'
|
||||
: days != null ? 'TA 随时会住进来,快去布置好'
|
||||
: '做孕期任务攒兜豆,一件件布置好';
|
||||
}
|
||||
(function nurseryInit() {
|
||||
const sec = $('#nursery');
|
||||
if (!sec) return;
|
||||
const card = $('#nyCard'), bub = $('#nyBubble');
|
||||
const still = window.matchMedia && matchMedia('(prefers-reduced-motion: reduce)').matches;
|
||||
card.addEventListener('click', () => {
|
||||
if (card.classList.contains('is-opening')) return;
|
||||
card.classList.add('is-opening');
|
||||
setTimeout(() => jumpApp(NURSERY_URL, NURSERY_ID), still ? 0 : 700);
|
||||
});
|
||||
/* 从婴儿房返回(bfcache 恢复)时把门关回虚掩 */
|
||||
window.addEventListener('pageshow', () => card.classList.remove('is-opening'));
|
||||
$('#nyBtn').addEventListener('click', () =>
|
||||
jumpApp(NURSERY_URL + '?return_url=' + encodeURIComponent(location.origin + location.pathname), NURSERY_ID));
|
||||
/* 视差:图层始终对齐 .screen 的可视区 → 页面滚、房间不动,像铺在整页背后 */
|
||||
const layer = $('#nypLayer'), scr = sec.closest('.screen');
|
||||
let raf = 0;
|
||||
const place = () => {
|
||||
raf = 0;
|
||||
if (!scr) return;
|
||||
const s = scr.getBoundingClientRect(), r = sec.getBoundingClientRect();
|
||||
if (!s.height || !r.height) return;
|
||||
layer.style.height = s.height + 'px';
|
||||
layer.style.transform = 'translate3d(0,' + Math.round(s.top - r.top) + 'px,0)';
|
||||
};
|
||||
const req = () => { if (!raf) raf = requestAnimationFrame(place); };
|
||||
if (scr) scr.addEventListener('scroll', req, { passive: true });
|
||||
window.addEventListener('resize', req);
|
||||
if ('IntersectionObserver' in window) new IntersectionObserver(req).observe(sec);
|
||||
place();
|
||||
const tick = () => {
|
||||
const h = new Date(Date.now() + 8 * 3600e3).getUTCHours(); // 北京时间
|
||||
sec.classList.toggle('is-night', h >= 19 || h < 6);
|
||||
};
|
||||
tick(); setInterval(tick, 600e3);
|
||||
/* 气泡轮播:一句 4.5 秒,淡出换下一句 */
|
||||
if (!still) setInterval(() => {
|
||||
if (nyLines.length < 2 || document.hidden) return;
|
||||
bub.classList.add('out');
|
||||
setTimeout(() => {
|
||||
nyLineIdx = (nyLineIdx + 1) % nyLines.length;
|
||||
bub.textContent = nyLines[nyLineIdx];
|
||||
bub.classList.remove('out');
|
||||
}, 350);
|
||||
}, 4500);
|
||||
nurseryRender();
|
||||
})();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user