115 lines
3.8 KiB
JavaScript
115 lines
3.8 KiB
JavaScript
|
|
/* ============================================================
|
||
|
|
About Us V3 — NIO-style animations
|
||
|
|
文字/Logo = 触发式(到达阈值 → 播完)
|
||
|
|
蒙版/背景缩放 = scrub 式(随滚动持续变化)
|
||
|
|
============================================================ */
|
||
|
|
(function () {
|
||
|
|
'use strict';
|
||
|
|
|
||
|
|
var s1 = document.getElementById('au-1');
|
||
|
|
var s3 = document.getElementById('au-3');
|
||
|
|
if (!s1) return;
|
||
|
|
|
||
|
|
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
|
||
|
|
document.documentElement.classList.add('rm');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
var pin1 = s1.closest('.au-pin');
|
||
|
|
var pin3 = s3 ? s3.closest('.au-pin') : null;
|
||
|
|
var mask1 = s1.querySelector('.au-mask');
|
||
|
|
var bg1 = s1.querySelector('.au-bg');
|
||
|
|
var mask3 = s3 ? s3.querySelector('.au-zoom-mask') : null;
|
||
|
|
|
||
|
|
function clamp(v, a, b) { return Math.max(a, Math.min(b, v)); }
|
||
|
|
|
||
|
|
function check() {
|
||
|
|
var y = window.scrollY;
|
||
|
|
var vh = window.innerHeight;
|
||
|
|
|
||
|
|
/* ---- au-1 ---- */
|
||
|
|
// 文字:触发式(过 30% → 加 .play)
|
||
|
|
var t1 = pin1.offsetTop + vh * 0.3;
|
||
|
|
s1.classList.toggle('play', y > t1);
|
||
|
|
|
||
|
|
// 蒙版:scrub 式(随滚动持续加深,0 → 1 跨 1.5 屏)
|
||
|
|
var p1 = clamp((y - pin1.offsetTop) / (vh * 1.5), 0, 1);
|
||
|
|
mask1.style.opacity = p1.toFixed(3);
|
||
|
|
|
||
|
|
// 背景:scrub 式(随滚动持续微缩 1.04 → 1)
|
||
|
|
bg1.style.transform = 'scale(' + (1.04 - 0.04 * p1).toFixed(4) + ')';
|
||
|
|
|
||
|
|
/* ---- au-3 ---- */
|
||
|
|
if (pin3) {
|
||
|
|
// 文字/Logo:触发式
|
||
|
|
var t3 = pin3.offsetTop + vh * 1.0;
|
||
|
|
s3.classList.toggle('play', y > t3);
|
||
|
|
|
||
|
|
// 黑幕:scrub 式(随滚动持续加深,0 → 0.8 跨 1.5 屏)
|
||
|
|
if (mask3) {
|
||
|
|
var p3 = clamp((y - pin3.offsetTop - vh * 0.5) / (vh * 1.5), 0, 1);
|
||
|
|
mask3.style.opacity = (p3 * 0.8).toFixed(3);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
var ticking = false;
|
||
|
|
window.addEventListener('scroll', function () {
|
||
|
|
if (ticking) return;
|
||
|
|
ticking = true;
|
||
|
|
requestAnimationFrame(function () { check(); ticking = false; });
|
||
|
|
}, { passive: true });
|
||
|
|
|
||
|
|
window.addEventListener('resize', function () {
|
||
|
|
pin1 = s1.closest('.au-pin');
|
||
|
|
pin3 = s3 ? s3.closest('.au-pin') : null;
|
||
|
|
check();
|
||
|
|
}, { passive: true });
|
||
|
|
|
||
|
|
check();
|
||
|
|
})();
|
||
|
|
|
||
|
|
/* GPS carousel */
|
||
|
|
(function () {
|
||
|
|
'use strict';
|
||
|
|
var viewport = document.querySelector('.au-gps__viewport');
|
||
|
|
var track = document.querySelector('.au-gps__track');
|
||
|
|
var dotsWrap = document.querySelector('.au-gps__dots');
|
||
|
|
if (!viewport || !track || !dotsWrap) return;
|
||
|
|
var cards = Array.prototype.slice.call(track.children);
|
||
|
|
if (cards.length < 2) return;
|
||
|
|
var idx = 0, timer = null;
|
||
|
|
|
||
|
|
cards.forEach(function (_, i) {
|
||
|
|
var b = document.createElement('button');
|
||
|
|
b.setAttribute('aria-label', 'Slide ' + (i + 1));
|
||
|
|
b.addEventListener('click', function () { goTo(i); restart(); });
|
||
|
|
dotsWrap.appendChild(b);
|
||
|
|
});
|
||
|
|
var dots = Array.prototype.slice.call(dotsWrap.children);
|
||
|
|
|
||
|
|
function render() {
|
||
|
|
track.style.transform = 'translateX(' + (-idx * 100) + '%)';
|
||
|
|
dots.forEach(function (d, i) { d.classList.toggle('active', i === idx); });
|
||
|
|
}
|
||
|
|
function goTo(i) { idx = ((i % cards.length) + cards.length) % cards.length; render(); }
|
||
|
|
function next() { goTo(idx + 1); }
|
||
|
|
function start() { if (!timer) timer = setInterval(next, 4000); }
|
||
|
|
function stop() { clearInterval(timer); timer = null; }
|
||
|
|
function restart(){ stop(); start(); }
|
||
|
|
|
||
|
|
render(); start();
|
||
|
|
viewport.addEventListener('mouseenter', stop);
|
||
|
|
viewport.addEventListener('mouseleave', start);
|
||
|
|
document.addEventListener('visibilitychange', function () {
|
||
|
|
document.hidden ? stop() : start();
|
||
|
|
});
|
||
|
|
var x0 = null;
|
||
|
|
viewport.addEventListener('pointerdown', function (e) { x0 = e.clientX; });
|
||
|
|
window.addEventListener('pointerup', function (e) {
|
||
|
|
if (x0 === null) return;
|
||
|
|
var dx = e.clientX - x0; x0 = null;
|
||
|
|
if (Math.abs(dx) > 40) { dx < 0 ? next() : goTo(idx - 1); restart(); }
|
||
|
|
});
|
||
|
|
})();
|