diff --git a/index.html b/index.html
index cacdd8b..ca0bfe0 100644
--- a/index.html
+++ b/index.html
@@ -974,106 +974,115 @@
// 移动端:入场动画 + 视差滚动
if (window.innerWidth <= 900) {
- // 移除 CSS scroll-snap(不可靠),用 JS 实现
- document.body.style.scrollSnapType = 'none';
- document.querySelectorAll('[style*="scroll-snap"]').forEach(el => {
- el.style.scrollSnapType = 'none';
- el.style.scrollSnapAlign = 'none';
- el.style.scrollSnapStop = 'normal';
- });
-
- // 1. 入场动画(一次性)
- const mobileItems = document.querySelectorAll('#pain-points .pain-item, #approach .approach-item');
- const mobileObserver = new IntersectionObserver((entries) => {
- entries.forEach(entry => {
- if (entry.isIntersecting) entry.target.classList.add('in-view');
- });
- }, { threshold: 0.05, rootMargin: "0px 0px -5% 0px" });
- mobileItems.forEach(item => mobileObserver.observe(item));
-
- // 2. 数字编号滚动视差(基于卡片相对视口位置)
- let ticking = false;
- const painNums = document.querySelectorAll('#pain-points .pain-num');
-
- function updateParallax() {
- painNums.forEach(num => {
- const card = num.parentElement;
- if (!card) return;
- const rect = card.getBoundingClientRect();
- const speed = 0.15;
- const yOffset = -(rect.top * speed);
- num.style.transform = `translateY(${yOffset}px)`;
- });
- ticking = false;
- }
-
- window.addEventListener('scroll', () => {
- if (!ticking) {
- requestAnimationFrame(updateParallax);
- ticking = true;
- }
- }, { passive: true });
- updateParallax();
-
- // 3. JS 逐屏吸附
- // 收集所有吸附点
+ // 3. 逐屏滚动 - 方向感知,禁止自由滚动
const snapTargets = [];
- // Hero
const hero = document.querySelector('.hero');
if (hero) snapTargets.push(hero);
- // 痛点每个卡片
document.querySelectorAll('#pain-points .pain-item').forEach(item => snapTargets.push(item));
- // 其他 section
['solutions', 'approach', 'geo', 'contact'].forEach(id => {
const el = document.getElementById(id);
if (el) snapTargets.push(el);
});
- let scrollEndTimer = null;
- let isSnapping = false;
+ let currentIndex = 0;
+ let isAnimating = false;
let touchStartY = 0;
- let lastScrollTop = 0;
+ let touchStartX = 0;
+ let animFrame = null;
- document.addEventListener('touchstart', (e) => {
- touchStartY = e.touches[0].clientY;
- }, { passive: true });
-
- window.addEventListener('scroll', () => {
- // 清除之前的定时器
- clearTimeout(scrollEndTimer);
- // 300ms 无滚动视为停止
- scrollEndTimer = setTimeout(() => {
- if (isSnapping) return; // 正在吸附中不触发
- snapToNearest();
- }, 200);
- lastScrollTop = window.scrollY;
- }, { passive: true });
-
- function snapToNearest() {
- const vh = window.innerHeight;
- const center = window.scrollY + vh * 0.4; // 吸附点偏上 40% 位置
-
- let nearest = null;
- let minDist = Infinity;
-
- snapTargets.forEach(target => {
- const rect = target.getBoundingClientRect();
- const top = rect.top + window.scrollY;
- const dist = Math.abs(top - center);
- if (dist < minDist) {
- minDist = dist;
- nearest = target;
+ // 找到离视口顶部最近的 section 索引
+ function findCurrentIndex() {
+ let best = 0;
+ let bestDist = Infinity;
+ snapTargets.forEach((target, i) => {
+ const top = target.getBoundingClientRect().top + window.scrollY;
+ const dist = Math.abs(top - window.scrollY);
+ if (dist < bestDist) {
+ bestDist = dist;
+ best = i;
}
});
-
- if (nearest) {
- isSnapping = true;
- const targetY = nearest.getBoundingClientRect().top + window.scrollY;
- window.scrollTo({ top: targetY, behavior: 'smooth' });
- // 吸附完成后解锁
- setTimeout(() => { isSnapping = false; }, 800);
- }
+ return best;
}
+
+ // 切换到指定 section
+ function goTo(index) {
+ if (index < 0 || index >= snapTargets.length || isAnimating) return;
+ isAnimating = true;
+ const targetY = snapTargets[index].getBoundingClientRect().top + window.scrollY;
+ const startY = window.scrollY;
+ const diff = targetY - startY;
+ const duration = 600;
+ const startTime = performance.now();
+
+ // 自定义缓动:先快后慢,有惯性感觉
+ function easeOutCubic(t) {
+ return 1 - Math.pow(1 - t, 3);
+ }
+
+ function step(now) {
+ const elapsed = now - startTime;
+ const progress = Math.min(elapsed / duration, 1);
+ const eased = easeOutCubic(progress);
+ window.scrollTo(0, startY + diff * eased);
+ if (progress < 1) {
+ animFrame = requestAnimationFrame(step);
+ } else {
+ isAnimating = false;
+ currentIndex = index;
+ }
+ }
+ animFrame = requestAnimationFrame(step);
+ }
+
+ // 初始化
+ currentIndex = findCurrentIndex();
+
+ // 完全接管触摸滚动 - 禁止原生滚动
+ let canScroll = true;
+ document.addEventListener('touchmove', (e) => {
+ e.preventDefault();
+ }, { passive: false });
+
+ document.addEventListener('touchstart', (e) => {
+ if (!canScroll || isAnimating) return;
+ touchStartY = e.touches[0].clientY;
+ touchStartX = e.touches[0].clientX;
+ }, { passive: true });
+
+ document.addEventListener('touchend', (e) => {
+ if (!canScroll || isAnimating) return;
+ const dy = touchStartY - e.changedTouches[0].clientY;
+ const dx = touchStartX - e.changedTouches[0].clientX;
+
+ // 水平滑动不处理(可能是浏览器前进后退手势)
+ if (Math.abs(dx) > Math.abs(dy)) return;
+ // 最小滑动阈值,防止误触
+ if (Math.abs(dy) < 40) return;
+
+ if (dy > 0) {
+ // 上滑 -> 下一屏
+ goTo(currentIndex + 1);
+ } else {
+ // 下滑 -> 上一屏
+ goTo(currentIndex - 1);
+ }
+ }, { passive: true });
+
+ // 导航链接点击:定位到对应 section 并更新索引
+ document.querySelectorAll('.nav-links a, .btn').forEach(link => {
+ link.addEventListener('click', (e) => {
+ const href = link.getAttribute('href');
+ if (!href || !href.startsWith('#')) return;
+ const targetId = href.substring(1);
+ const idx = snapTargets.findIndex(t => t.id === targetId);
+ if (idx >= 0) {
+ e.preventDefault();
+ currentIndex = idx;
+ goTo(idx);
+ }
+ });
+ });
}