Files
aijianhua/website/js/main.js

514 lines
15 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 主JavaScript文件 - 爱鉴花官方网站
document.addEventListener('DOMContentLoaded', function() {
// 初始化函数
initWebsite();
});
function initWebsite() {
// 初始化导航栏滚动效果
initNavbarScroll();
// 初始化滚动动画
initScrollAnimation();
// 初始化表单验证
initFormValidation();
// 初始化计数器动画
initCounterAnimation();
// 初始化图片懒加载
initLazyLoading();
// 初始化移动端菜单
initMobileMenu();
// 初始化平滑滚动
initSmoothScroll();
// 初始化悬停动画
initHoverEffects();
// 初始化加载状态
initLoadingStates();
// 初始化页面过渡效果
initPageTransitions();
}
// 导航栏滚动效果
function initNavbarScroll() {
const navbar = document.querySelector('.navbar');
window.addEventListener('scroll', function() {
if (window.scrollY > 100) {
navbar.classList.add('navbar-scrolled');
} else {
navbar.classList.remove('navbar-scrolled');
}
});
}
// 滚动动画效果
function initScrollAnimation() {
const animatedElements = document.querySelectorAll('.card, .feature-icon');
const observerOptions = {
threshold: 0.1,
rootMargin: '0px 0px -50px 0px'
};
const observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
entry.target.classList.add('fade-in-up');
observer.unobserve(entry.target);
}
});
}, observerOptions);
animatedElements.forEach(function(element) {
observer.observe(element);
});
}
// 表单验证
function initFormValidation() {
const forms = document.querySelectorAll('form');
forms.forEach(function(form) {
form.addEventListener('submit', function(e) {
if (!validateForm(form)) {
e.preventDefault();
}
});
});
}
function validateForm(form) {
let isValid = true;
const inputs = form.querySelectorAll('input[required], textarea[required]');
inputs.forEach(function(input) {
if (!input.value.trim()) {
showError(input, '此字段为必填项');
isValid = false;
} else if (input.type === 'email' && !isValidEmail(input.value)) {
showError(input, '请输入有效的邮箱地址');
isValid = false;
} else {
clearError(input);
}
});
return isValid;
}
function isValidEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
function showError(input, message) {
clearError(input);
const errorDiv = document.createElement('div');
errorDiv.className = 'invalid-feedback';
errorDiv.textContent = message;
input.classList.add('is-invalid');
input.parentNode.appendChild(errorDiv);
}
function clearError(input) {
input.classList.remove('is-invalid');
const errorDiv = input.parentNode.querySelector('.invalid-feedback');
if (errorDiv) {
errorDiv.remove();
}
}
// 计数器动画
function initCounterAnimation() {
const counters = document.querySelectorAll('.counter');
if (counters.length > 0) {
const observer = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
animateCounters();
observer.unobserve(entry.target);
}
});
});
observer.observe(counters[0]);
}
}
function animateCounters() {
const counters = document.querySelectorAll('.counter');
counters.forEach(function(counter) {
const target = parseInt(counter.getAttribute('data-target'));
const duration = 2000; // 2 seconds
const frameDuration = 1000 / 60; // 60fps
const totalFrames = Math.round(duration / frameDuration);
let currentFrame = 0;
const updateCounter = function() {
currentFrame++;
const progress = currentFrame / totalFrames;
const currentValue = Math.round(target * progress);
counter.textContent = currentValue.toLocaleString();
if (currentFrame < totalFrames) {
requestAnimationFrame(updateCounter);
} else {
counter.textContent = target.toLocaleString();
}
};
updateCounter();
});
}
// 图片懒加载
function initLazyLoading() {
if ('IntersectionObserver' in window) {
const lazyImages = document.querySelectorAll('img.lazy-load');
const imageObserver = new IntersectionObserver(function(entries) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
const img = entry.target;
// 确保图片完全加载后显示
img.onload = function() {
img.classList.add('loaded');
};
// 处理data-src属性或直接使用src
if (img.hasAttribute('data-src')) {
img.src = img.getAttribute('data-src');
img.removeAttribute('data-src');
}
imageObserver.unobserve(img);
}
});
}, {
threshold: 0.1,
rootMargin: '50px 0px'
});
lazyImages.forEach(function(img) {
imageObserver.observe(img);
});
} else {
// 浏览器不支持IntersectionObserver时的降级方案
const lazyImages = document.querySelectorAll('img.lazy-load');
lazyImages.forEach(function(img) {
img.classList.add('loaded');
});
}
}
// 移动端菜单处理
function initMobileMenu() {
const navbarToggler = document.querySelector('.navbar-toggler');
const navbarCollapse = document.querySelector('.navbar-collapse');
if (navbarToggler && navbarCollapse) {
navbarToggler.addEventListener('click', function() {
navbarCollapse.classList.toggle('show');
// 添加菜单动画效果
navbarToggler.classList.toggle('active');
});
// 点击菜单项后自动关闭菜单(移动端)
const navLinks = document.querySelectorAll('.navbar-nav .nav-link');
navLinks.forEach(function(link) {
link.addEventListener('click', function() {
if (window.innerWidth < 992) {
navbarCollapse.classList.remove('show');
navbarToggler.classList.remove('active');
}
});
});
}
}
// 平滑滚动效果
function initSmoothScroll() {
// 内部链接平滑滚动
const internalLinks = document.querySelectorAll('a[href^="#"]');
internalLinks.forEach(function(link) {
link.addEventListener('click', function(e) {
e.preventDefault();
const targetId = this.getAttribute('href').substring(1);
const targetElement = document.getElementById(targetId);
if (targetElement) {
const offsetTop = targetElement.offsetTop - 80; // 考虑导航栏高度
window.scrollTo({
top: offsetTop,
behavior: 'smooth'
});
}
});
});
// 返回顶部按钮
const backToTopBtn = document.createElement('button');
backToTopBtn.className = 'back-to-top';
backToTopBtn.innerHTML = '↑';
backToTopBtn.setAttribute('aria-label', '返回顶部');
backToTopBtn.addEventListener('click', function() {
window.scrollTo({
top: 0,
behavior: 'smooth'
});
});
// 滚动时显示/隐藏返回顶部按钮
window.addEventListener('scroll', debounce(function() {
if (window.scrollY > 500) {
backToTopBtn.classList.add('show');
} else {
backToTopBtn.classList.remove('show');
}
}, 100));
document.body.appendChild(backToTopBtn);
}
// 悬停动画效果
function initHoverEffects() {
// 卡片悬停效果
const cards = document.querySelectorAll('.card, .product-card, .news-card');
cards.forEach(function(card) {
card.addEventListener('mouseenter', function() {
this.style.transform = 'translateY(-5px) scale(1.02)';
this.style.boxShadow = '0 10px 25px rgba(0, 0, 0, 0.15)';
});
card.addEventListener('mouseleave', function() {
this.style.transform = 'translateY(0) scale(1)';
this.style.boxShadow = '0 4px 6px rgba(0, 0, 0, 0.1)';
});
});
// 按钮悬停效果
const buttons = document.querySelectorAll('.btn, .nav-link');
buttons.forEach(function(button) {
button.addEventListener('mouseenter', function() {
this.style.transform = 'translateY(-2px)';
});
button.addEventListener('mouseleave', function() {
this.style.transform = 'translateY(0)';
});
});
}
// 加载状态指示器
function initLoadingStates() {
const forms = document.querySelectorAll('form');
forms.forEach(function(form) {
form.addEventListener('submit', function() {
const submitBtn = this.querySelector('button[type="submit"]');
if (submitBtn) {
submitBtn.disabled = true;
submitBtn.innerHTML = '<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span> 处理中...';
// 3秒后恢复按钮状态防止无限加载
setTimeout(function() {
submitBtn.disabled = false;
submitBtn.innerHTML = submitBtn.getAttribute('data-original-text') || '提交';
}, 3000);
}
});
});
// 保存按钮原始文本
document.addEventListener('DOMContentLoaded', function() {
const submitButtons = document.querySelectorAll('button[type="submit"]');
submitButtons.forEach(function(btn) {
btn.setAttribute('data-original-text', btn.textContent);
});
});
}
// 页面过渡效果
function initPageTransitions() {
// 链接点击时的过渡效果
const links = document.querySelectorAll('a:not([href^="#"]):not([href^="javascript"])');
links.forEach(function(link) {
link.addEventListener('click', function(e) {
if (this.href && !this.target && !this.hasAttribute('download')) {
e.preventDefault();
// 添加页面离开动画
document.body.classList.add('page-leaving');
setTimeout(function() {
window.location.href = link.href;
}, 300);
}
});
});
// 页面进入动画
document.body.classList.add('page-entering');
setTimeout(function() {
document.body.classList.remove('page-entering');
}, 300);
}
// 工具函数:防抖
function debounce(func, wait) {
let timeout;
return function() {
const context = this;
const args = arguments;
clearTimeout(timeout);
timeout = setTimeout(function() {
func.apply(context, args);
}, wait);
};
}
// 工具函数:节流
function throttle(func, limit) {
let inThrottle;
return function() {
const args = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(function() {
inThrottle = false;
}, limit);
}
};
}
// 页面性能监控
function monitorPerformance() {
// 页面加载时间
window.addEventListener('load', function() {
const loadTime = performance.timing.loadEventEnd - performance.timing.navigationStart;
console.log('页面加载时间:', loadTime + 'ms');
});
// 最大内容绘制LCP
new PerformanceObserver(function(entryList) {
const entries = entryList.getEntries();
const lastEntry = entries[entries.length - 1];
console.log('LCP:', lastEntry.startTime);
}).observe({type: 'largest-contentful-paint', buffered: true});
}
// 错误监控
function monitorErrors() {
window.addEventListener('error', function(e) {
console.error('JavaScript错误:', e.error);
});
window.addEventListener('unhandledrejection', function(e) {
console.error('未处理的Promise拒绝:', e.reason);
});
}
// 初始化性能和错误监控
monitorPerformance();
monitorErrors();
// 通用JavaScript功能
// 导航栏滚动效果
window.addEventListener('scroll', function() {
const navbar = document.querySelector('.navbar');
if (window.scrollY > 50) {
navbar.classList.add('scrolled');
} else {
navbar.classList.remove('scrolled');
}
});
// 懒加载图片
document.addEventListener('DOMContentLoaded', function() {
const lazyImages = [].slice.call(document.querySelectorAll('img.lazy-load'));
if ('IntersectionObserver' in window) {
let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
let lazyImage = entry.target;
lazyImage.src = lazyImage.dataset.src || lazyImage.src;
lazyImage.classList.remove('lazy-load');
lazyImageObserver.unobserve(lazyImage);
}
});
});
lazyImages.forEach(function(lazyImage) {
lazyImageObserver.observe(lazyImage);
});
}
});
// 平滑滚动
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
anchor.addEventListener('click', function (e) {
e.preventDefault();
const target = document.querySelector(this.getAttribute('href'));
if (target) {
window.scrollTo({
top: target.offsetTop - 76,
behavior: 'smooth'
});
}
});
});
// 表单验证增强
(function() {
'use strict';
window.addEventListener('load', function() {
// 获取所有表单并阻止默认提交行为
var forms = document.getElementsByClassName('needs-validation');
var validation = Array.prototype.filter.call(forms, function(form) {
form.addEventListener('submit', function(event) {
if (form.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
}
form.classList.add('was-validated');
}, false);
});
}, false);
})();
// 动态年份更新
document.addEventListener('DOMContentLoaded', function() {
const yearElements = document.querySelectorAll('.current-year');
const currentYear = new Date().getFullYear();
yearElements.forEach(element => {
element.textContent = currentYear;
});
});