/** * 智慧时间轴组件 - 横向展开式 * Smart Timeline Component - Horizontal Expansion */ (function() { 'use strict'; // 等待DOM加载完成 document.addEventListener('DOMContentLoaded', initTimeline); function initTimeline() { const container = document.querySelector('.timeline-container'); if (!container) return; const items = container.querySelectorAll('.timeline-item'); if (!items.length) return; // 入场动画 - 使用 Intersection Observer const observerOptions = { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { animateItems(); observer.unobserve(entry.target); } }); }, observerOptions); observer.observe(container); // 节点逐个入场动画 function animateItems() { items.forEach((item, index) => { setTimeout(() => { item.style.opacity = '1'; item.style.transform = 'translateY(0)'; }, index * 80); }); } // 初始化节点样式(用于动画) items.forEach(item => { item.style.opacity = '0'; item.style.transform = 'translateY(20px)'; item.style.transition = 'opacity 0.5s ease, transform 0.5s ease, flex 0.5s cubic-bezier(0.25, 0.1, 0.25, 1), background 0.5s ease'; }); // 触摸设备支持 let touchStartX = null; let scrollLeft = null; container.addEventListener('touchstart', (e) => { touchStartX = e.touches[0].pageX; scrollLeft = container.scrollLeft; }, { passive: true }); container.addEventListener('touchmove', (e) => { if (!touchStartX) return; const x = e.touches[0].pageX; const walk = (touchStartX - x) * 1.5; container.scrollLeft = scrollLeft + walk; }, { passive: true }); container.addEventListener('touchend', () => { touchStartX = null; }); // 鼠标滚轮横向滚动(移动端视图时) container.addEventListener('wheel', (e) => { if (container.scrollWidth > container.clientWidth) { if (Math.abs(e.deltaX) < Math.abs(e.deltaY)) { e.preventDefault(); container.scrollLeft += e.deltaY; } } }, { passive: false }); // 拖拽滚动(移动端视图时) let isDragging = false; let startX; let dragScrollLeft; container.addEventListener('mousedown', (e) => { if (container.scrollWidth <= container.clientWidth) return; if (e.target.closest('.timeline-item')) return; isDragging = true; container.style.cursor = 'grabbing'; startX = e.pageX - container.offsetLeft; dragScrollLeft = container.scrollLeft; }); container.addEventListener('mouseleave', () => { isDragging = false; container.style.cursor = ''; }); container.addEventListener('mouseup', () => { isDragging = false; container.style.cursor = ''; }); container.addEventListener('mousemove', (e) => { if (!isDragging) return; e.preventDefault(); const x = e.pageX - container.offsetLeft; const walk = (x - startX) * 2; container.scrollLeft = dragScrollLeft - walk; }); // 节点点击事件(可扩展) items.forEach((item) => { item.addEventListener('click', () => { // 添加点击反馈动画 const dot = item.querySelector('.dot'); if (dot) { dot.style.transform = 'translate(-50%, -50%) scale(2)'; setTimeout(() => { dot.style.transform = ''; }, 200); } }); }); // 键盘导航支持 let currentIndex = 0; document.addEventListener('keydown', (e) => { if (!isElementInViewport(container)) return; if (e.key === 'ArrowLeft') { currentIndex = Math.max(0, currentIndex - 1); scrollToItem(currentIndex); } else if (e.key === 'ArrowRight') { currentIndex = Math.min(items.length - 1, currentIndex + 1); scrollToItem(currentIndex); } }); function scrollToItem(index) { if (container.scrollWidth <= container.clientWidth) return; const item = items[index]; if (!item) return; const containerRect = container.getBoundingClientRect(); const itemRect = item.getBoundingClientRect(); const targetScrollLeft = container.scrollLeft + (itemRect.left - containerRect.left) - (containerRect.width / 2) + (itemRect.width / 2); container.scrollTo({ left: targetScrollLeft, behavior: 'smooth' }); } // ============================================ // 自动轮播功能 - 从左到右循环展开 // ============================================ let autoPlayIndex = 0; let autoPlayTimer = null; let isUserInteracting = false; const autoPlayInterval = 3000; // 每个节点展开持续时间(毫秒) const pauseAfterInteraction = 5000; // 用户交互后暂停时间(毫秒) // 添加自动展开的CSS类 function expandItem(index) { // 移除所有节点的展开状态 items.forEach(item => { item.classList.remove('auto-expanded'); }); // 给当前节点添加展开状态 if (items[index]) { items[index].classList.add('auto-expanded'); } } // 自动轮播 function autoPlay() { if (isUserInteracting) return; expandItem(autoPlayIndex); autoPlayIndex = (autoPlayIndex + 1) % items.length; } // 启动自动轮播 function startAutoPlay() { if (autoPlayTimer) return; autoPlayTimer = setInterval(autoPlay, autoPlayInterval); // 立即展开第一个 autoPlay(); } // 停止自动轮播 function stopAutoPlay() { if (autoPlayTimer) { clearInterval(autoPlayTimer); autoPlayTimer = null; } // 移除所有展开状态 items.forEach(item => { item.classList.remove('auto-expanded'); }); } // 用户交互时暂停自动轮播 function pauseAutoPlay() { isUserInteracting = true; stopAutoPlay(); // 一段时间后恢复自动轮播 setTimeout(() => { isUserInteracting = false; if (isElementInViewport(container)) { startAutoPlay(); } }, pauseAfterInteraction); } // 监听用户交互 container.addEventListener('mouseenter', pauseAutoPlay); container.addEventListener('touchstart', pauseAutoPlay, { passive: true }); // 使用 Intersection Observer 控制自动轮播 const autoPlayObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting && !isUserInteracting) { startAutoPlay(); } else { stopAutoPlay(); } }); }, { threshold: 0.3 }); autoPlayObserver.observe(container); console.log("Timeline Loaded with Enhanced Labels and Positioning"); } // 工具函数:检查元素是否在视口中 function isElementInViewport(el) { const rect = el.getBoundingClientRect(); return ( rect.top < window.innerHeight && rect.bottom > 0 ); } })();