/** * AKSRT Effects — count-up / countdown / marquee / 3D tilt / FPS detection * * 全部渐进增强,尊重 prefers-reduced-motion。 * * @package AKSRT */ (function () { 'use strict'; var reducedMotion = window.matchMedia && window.matchMedia('(prefers-reduced-motion: reduce)').matches; /* ============================================================ * 1. 数字递增 (count-up) — IntersectionObserver 触发 * 用法:0 * ============================================================ */ function initCountUp() { if (reducedMotion) return; if (!('IntersectionObserver' in window)) return; var els = document.querySelectorAll('[data-aksrt-countup]'); if (!els.length) return; var observer = new IntersectionObserver(function (entries) { entries.forEach(function (entry) { if (!entry.isIntersecting) return; var el = entry.target; observer.unobserve(el); var target = parseFloat(el.dataset.target || '0'); var duration = parseInt(el.dataset.duration || '2000', 10); var decimals = (el.dataset.decimals || '0|').split('|'); var prefix = decimals[1] || ''; var dec = parseInt(decimals[0], 10) || 0; var start = 0; var startTime = null; function step(timestamp) { if (!startTime) startTime = timestamp; var progress = Math.min((timestamp - startTime) / duration, 1); // ease-out cubic var eased = 1 - Math.pow(1 - progress, 3); var current = start + (target - start) * eased; el.textContent = prefix + current.toFixed(dec).replace(/\B(?=(\d{3})+(?!\d))/g, ','); if (progress < 1) { requestAnimationFrame(step); } else { el.textContent = prefix + target.toFixed(dec).replace(/\B(?=(\d{3})+(?!\d))/g, ','); } } requestAnimationFrame(step); }); }, { threshold: 0.3 }); els.forEach(function (el) { observer.observe(el); }); } /* ============================================================ * 2. 倒计时组件 * 用法:--:--:-- * ============================================================ */ function initCountdown() { var els = document.querySelectorAll('[data-aksrt-countdown]'); if (!els.length) return; function pad(n) { return n < 10 ? '0' + n : '' + n; } function update() { var now = Date.now(); els.forEach(function (el) { var end = new Date(el.dataset.end).getTime(); var diff = end - now; if (diff <= 0) { el.textContent = el.dataset.expired || '已结束'; return; } var d = Math.floor(diff / 86400000); var h = Math.floor((diff % 86400000) / 3600000); var m = Math.floor((diff % 3600000) / 60000); var s = Math.floor((diff % 60000) / 1000); var format = el.dataset.format || 'dhms'; if (format === 'dhms') { el.textContent = (d > 0 ? d + '天 ' : '') + pad(h) + ':' + pad(m) + ':' + pad(s); } else if (format === 'hms') { el.textContent = pad(h + d * 24) + ':' + pad(m) + ':' + pad(s); } else { el.textContent = (d > 0 ? d + '天 ' : '') + pad(h) + '时' + pad(m) + '分' + pad(s) + '秒'; } }); } update(); setInterval(update, 1000); } /* ============================================================ * 4. 3D 悬停倾斜 (vanilla tilt) * 用法: