- design/: Figma 设计稿提取产物 — 设计规范文档、9 张整屏预览、 8 个 SVG 组件切图、15 张位图素材、完整节点数据(full.json) - h5/: 纯静态 H5 实现 — 启动页/隐私弹窗/档案填写(肤质轮播)/ 三连拍照/报告页,375px 基准还原,含压缩素材与 Playwright 验收截图
186 lines
7.0 KiB
JavaScript
186 lines
7.0 KiB
JavaScript
/* ═════ 巨子测肤 H5 — 交互逻辑 ═════ */
|
|
(function () {
|
|
'use strict';
|
|
|
|
var $ = function (sel, root) { return (root || document).querySelector(sel); };
|
|
|
|
/* ─── Toast ─── */
|
|
var toastEl = $('#toast'), toastTimer = null;
|
|
function toast(msg) {
|
|
toastEl.textContent = msg;
|
|
toastEl.classList.add('show');
|
|
clearTimeout(toastTimer);
|
|
toastTimer = setTimeout(function () { toastEl.classList.remove('show'); }, 1800);
|
|
}
|
|
|
|
/* ─── 屏幕管理 ─── */
|
|
var currentScreen = 's-splash';
|
|
function showScreen(id) {
|
|
document.querySelectorAll('.screen').forEach(function (s) {
|
|
s.classList.toggle('active', s.id === id);
|
|
});
|
|
var sc = document.getElementById(id);
|
|
sc.scrollTop = 0;
|
|
currentScreen = id;
|
|
}
|
|
|
|
/* ─── 弹窗管理 ─── */
|
|
function openOverlay(id) { $('#' + id).classList.add('show'); }
|
|
function closeOverlay(id) { $('#' + id).classList.remove('show'); }
|
|
|
|
/* ─── 肤质轮播 ─── */
|
|
var SKINS = [
|
|
{ img: 'assets/img/skin-0-dry.png', name: '干性肌肤', desc: '全脸干燥,容易紧绷、缺乏光泽' },
|
|
{ img: 'assets/img/skin-1-mixeddry.png', name: '混合偏干肌肤', desc: '两颊偏干,T区油脂较少或偶尔出油' },
|
|
{ img: 'assets/img/skin-2-neutral.png', name: '中性肌肤', desc: '水油平衡,肤感舒适,无明显干燥出油' },
|
|
{ img: 'assets/img/skin-3-oily.png', name: '油性肌肤', desc: '全脸易出油,容易泛油光、毛孔明显' },
|
|
{ img: 'assets/img/skin-4-mixedoily.png', name: '混合偏油肌肤', desc: 'T区易出油,两颊相对清爽或轻微干燥' }
|
|
];
|
|
var skinIndex = 0;
|
|
var track = $('#skin-track'), dotsBox = $('#skin-dots');
|
|
|
|
SKINS.forEach(function (s, i) {
|
|
var item = document.createElement('div');
|
|
item.className = 'skin-item';
|
|
item.innerHTML =
|
|
'<img src="' + s.img + '" alt="' + s.name + '">' +
|
|
'<span class="skin-name">' + s.name + '</span>' +
|
|
'<p class="skin-desc">' + s.desc + '</p>';
|
|
track.appendChild(item);
|
|
var dot = document.createElement('i');
|
|
if (i === 0) dot.className = 'on';
|
|
dot.addEventListener('click', function () { goSkin(i); });
|
|
dotsBox.appendChild(dot);
|
|
});
|
|
|
|
function goSkin(i) {
|
|
skinIndex = Math.max(0, Math.min(SKINS.length - 1, i));
|
|
track.style.transform = 'translateX(-' + skinIndex * 100 + '%)';
|
|
dotsBox.querySelectorAll('i').forEach(function (d, k) {
|
|
d.classList.toggle('on', k === skinIndex);
|
|
});
|
|
}
|
|
|
|
// 触摸滑动
|
|
var touchX = null;
|
|
$('#skin-carousel').addEventListener('touchstart', function (e) {
|
|
touchX = e.touches[0].clientX;
|
|
}, { passive: true });
|
|
$('#skin-carousel').addEventListener('touchend', function (e) {
|
|
if (touchX === null) return;
|
|
var dx = e.changedTouches[0].clientX - touchX;
|
|
if (Math.abs(dx) > 30) goSkin(skinIndex + (dx < 0 ? 1 : -1));
|
|
touchX = null;
|
|
}, { passive: true });
|
|
|
|
/* ─── 地区选项 ─── */
|
|
var REGIONS = ['北京', '上海', '广州', '深圳', '杭州', '成都', '重庆', '武汉', '西安', '南京', '天津', '苏州', '长沙', '郑州', '青岛', '其他'];
|
|
var regionSel = $('#f-region');
|
|
REGIONS.forEach(function (r) {
|
|
var o = document.createElement('option');
|
|
o.textContent = r;
|
|
regionSel.appendChild(o);
|
|
});
|
|
|
|
/* ─── 拍照流程 ─── */
|
|
var CAM_STEPS = [
|
|
{ bg: 'assets/img/cam-front.jpg', step: '1/3<br>请单人正脸出镜', guides: ['正脸居中', '取下眼镜', '光线充足'] },
|
|
{ bg: 'assets/img/cam-left.jpg', step: '2/3<br>请单人右脸出镜', guides: ['右脸居中', '取下眼镜', '光线充足'] },
|
|
{ bg: 'assets/img/cam-right.jpg', step: '3/3<br>请单人左脸出镜', guides: ['左脸居中', '取下眼镜', '光线充足'] }
|
|
];
|
|
var camStep = 0;
|
|
|
|
function renderCamStep() {
|
|
var cfg = CAM_STEPS[camStep];
|
|
$('#cam-bg').style.backgroundImage = 'url(' + cfg.bg + ')';
|
|
$('#cam-step').innerHTML = cfg.step;
|
|
$('#cam-guide').innerHTML = cfg.guides
|
|
.map(function (g) { return '<span>' + g + '</span>'; })
|
|
.join('<i></i>');
|
|
}
|
|
|
|
function shutter() {
|
|
var flash = $('#cam-flash');
|
|
flash.classList.add('on');
|
|
setTimeout(function () { flash.classList.remove('on'); }, 220);
|
|
setTimeout(function () {
|
|
if (camStep < CAM_STEPS.length - 1) {
|
|
camStep++;
|
|
renderCamStep();
|
|
} else {
|
|
camStep = 0;
|
|
renderCamStep();
|
|
openOverlay('p-analyzing');
|
|
setTimeout(function () {
|
|
closeOverlay('p-analyzing');
|
|
showScreen('s-report');
|
|
}, 1600);
|
|
}
|
|
}, 260);
|
|
}
|
|
|
|
/* ─── 隐私勾选 ─── */
|
|
var agreed = false;
|
|
$('#privacy-row').addEventListener('click', function (e) {
|
|
e.preventDefault();
|
|
agreed = !agreed;
|
|
$('#privacy-check').classList.toggle('checked', agreed);
|
|
});
|
|
|
|
/* ─── 报告页 Tab ─── */
|
|
$('#detail-tabs').addEventListener('click', function (e) {
|
|
var btn = e.target.closest('.dtab');
|
|
if (!btn) return;
|
|
var idx = btn.dataset.tab;
|
|
document.querySelectorAll('.dtab').forEach(function (t) { t.classList.toggle('active', t === btn); });
|
|
document.querySelectorAll('.dpanel').forEach(function (p) {
|
|
p.classList.toggle('active', p.dataset.panel === idx);
|
|
});
|
|
});
|
|
|
|
/* ─── 动作分发 ─── */
|
|
var actions = {
|
|
'open-privacy': function () { openOverlay('p-privacy'); },
|
|
'close-privacy': function () { closeOverlay('p-privacy'); },
|
|
'agree-continue': function () {
|
|
if (!agreed) { toast('请先阅读并同意隐私协议'); return; }
|
|
closeOverlay('p-privacy');
|
|
showScreen('s-profile');
|
|
},
|
|
'back-splash': function () { showScreen('s-splash'); },
|
|
'submit-profile': function () {
|
|
var age = $('#f-age').value.trim();
|
|
if (!age || !/^\d{1,2}$/.test(age) || +age < 1 || +age > 99) { toast('请输入有效年龄'); return; }
|
|
if (!$('#f-gender').value) { toast('请选择性别'); return; }
|
|
if (!regionSel.value) { toast('请选择所在地区'); return; }
|
|
openOverlay('p-photoguide');
|
|
},
|
|
'close-photoguide': function () { closeOverlay('p-photoguide'); },
|
|
'start-camera': function () {
|
|
closeOverlay('p-photoguide');
|
|
camStep = 0;
|
|
renderCamStep();
|
|
showScreen('s-cam');
|
|
},
|
|
'cam-back': function () {
|
|
if (camStep > 0) { camStep--; renderCamStep(); }
|
|
else { showScreen('s-profile'); }
|
|
},
|
|
'shutter': shutter,
|
|
'album': function () { toast('相册功能开发中'); },
|
|
'flip': function () { toast('切换镜头功能开发中'); },
|
|
'back-profile': function () { showScreen('s-profile'); },
|
|
'more': function () { toast('了解更多功能开发中'); }
|
|
};
|
|
|
|
document.addEventListener('click', function (e) {
|
|
var el = e.target.closest('[data-action]');
|
|
if (!el) return;
|
|
var fn = actions[el.dataset.action];
|
|
if (fn) fn();
|
|
});
|
|
|
|
/* ─── 初始化 ─── */
|
|
renderCamStep();
|
|
})();
|