制作官网website
This commit is contained in:
260
website/assets/js/script.js
Normal file
260
website/assets/js/script.js
Normal file
@@ -0,0 +1,260 @@
|
||||
// 页面加载完成后执行
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// 初始化导航栏滚动效果
|
||||
initNavbarScroll();
|
||||
|
||||
// 初始化滚动动画
|
||||
initScrollAnimation();
|
||||
|
||||
// 初始化表单验证
|
||||
initFormValidation();
|
||||
|
||||
// 初始化数据统计动画
|
||||
initStatsCounter();
|
||||
});
|
||||
|
||||
// 导航栏滚动效果
|
||||
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 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('animate__animated', 'animate__fadeInUp');
|
||||
}
|
||||
});
|
||||
}, observerOptions);
|
||||
|
||||
// 观察需要动画的元素
|
||||
const animatedElements = document.querySelectorAll('.feature-card, .case-card, .news-card, .tech-item');
|
||||
animatedElements.forEach(function(el) {
|
||||
observer.observe(el);
|
||||
});
|
||||
}
|
||||
|
||||
// 表单验证
|
||||
function initFormValidation() {
|
||||
const contactForm = document.querySelector('.contact-form form');
|
||||
|
||||
if (contactForm) {
|
||||
contactForm.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (validateForm(this)) {
|
||||
// 模拟表单提交
|
||||
showFormLoading();
|
||||
|
||||
setTimeout(function() {
|
||||
hideFormLoading();
|
||||
showFormSuccess();
|
||||
contactForm.reset();
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 表单验证函数
|
||||
function validateForm(form) {
|
||||
let isValid = true;
|
||||
const inputs = form.querySelectorAll('input, textarea');
|
||||
|
||||
inputs.forEach(function(input) {
|
||||
if (input.hasAttribute('required') && !input.value.trim()) {
|
||||
showInputError(input, '此字段为必填项');
|
||||
isValid = false;
|
||||
} else if (input.type === 'email' && !isValidEmail(input.value)) {
|
||||
showInputError(input, '请输入有效的邮箱地址');
|
||||
isValid = false;
|
||||
} else {
|
||||
clearInputError(input);
|
||||
}
|
||||
});
|
||||
|
||||
return isValid;
|
||||
}
|
||||
|
||||
// 邮箱验证
|
||||
function isValidEmail(email) {
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
return emailRegex.test(email);
|
||||
}
|
||||
|
||||
// 显示输入错误
|
||||
function showInputError(input, message) {
|
||||
clearInputError(input);
|
||||
|
||||
const errorDiv = document.createElement('div');
|
||||
errorDiv.className = 'invalid-feedback';
|
||||
errorDiv.textContent = message;
|
||||
|
||||
input.classList.add('is-invalid');
|
||||
input.parentNode.appendChild(errorDiv);
|
||||
}
|
||||
|
||||
// 清除输入错误
|
||||
function clearInputError(input) {
|
||||
input.classList.remove('is-invalid');
|
||||
const errorDiv = input.parentNode.querySelector('.invalid-feedback');
|
||||
if (errorDiv) {
|
||||
errorDiv.remove();
|
||||
}
|
||||
}
|
||||
|
||||
// 显示表单加载状态
|
||||
function showFormLoading() {
|
||||
const submitBtn = document.querySelector('.contact-form button[type="submit"]');
|
||||
const originalText = submitBtn.textContent;
|
||||
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.innerHTML = '<span class="loading"></span> 发送中...';
|
||||
submitBtn.setAttribute('data-original-text', originalText);
|
||||
}
|
||||
|
||||
// 隐藏表单加载状态
|
||||
function hideFormLoading() {
|
||||
const submitBtn = document.querySelector('.contact-form button[type="submit"]');
|
||||
const originalText = submitBtn.getAttribute('data-original-text');
|
||||
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.textContent = originalText;
|
||||
}
|
||||
|
||||
// 显示表单成功消息
|
||||
function showFormSuccess() {
|
||||
// 创建成功消息提示
|
||||
const successAlert = document.createElement('div');
|
||||
successAlert.className = 'alert alert-success mt-3';
|
||||
successAlert.innerHTML = '\
|
||||
<i class="bi bi-check-circle-fill me-2"></i>\
|
||||
消息发送成功!我们会尽快回复您。\
|
||||
';
|
||||
|
||||
const form = document.querySelector('.contact-form form');
|
||||
form.appendChild(successAlert);
|
||||
|
||||
// 3秒后自动隐藏
|
||||
setTimeout(function() {
|
||||
successAlert.remove();
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
// 数据统计计数器动画
|
||||
function initStatsCounter() {
|
||||
const statsSection = document.querySelector('.stats-section');
|
||||
const statNumbers = document.querySelectorAll('.stat-item h3');
|
||||
let hasAnimated = false;
|
||||
|
||||
const observer = new IntersectionObserver(function(entries) {
|
||||
entries.forEach(function(entry) {
|
||||
if (entry.isIntersecting && !hasAnimated) {
|
||||
hasAnimated = true;
|
||||
animateStats();
|
||||
}
|
||||
});
|
||||
}, { threshold: 0.5 });
|
||||
|
||||
if (statsSection) {
|
||||
observer.observe(statsSection);
|
||||
}
|
||||
}
|
||||
|
||||
// 数字动画效果
|
||||
function animateStats() {
|
||||
const statNumbers = document.querySelectorAll('.stat-item h3');
|
||||
|
||||
statNumbers.forEach(function(stat) {
|
||||
const target = parseInt(stat.textContent.replace(/[^0-9]/g, ''));
|
||||
const duration = 2000; // 动画时长2秒
|
||||
const frameDuration = 1000 / 60; // 60fps
|
||||
const totalFrames = Math.round(duration / frameDuration);
|
||||
let frame = 0;
|
||||
|
||||
const originalText = stat.textContent;
|
||||
|
||||
const counter = setInterval(function() {
|
||||
frame++;
|
||||
|
||||
// 缓动函数
|
||||
const progress = frame / totalFrames;
|
||||
const easeOutQuart = 1 - Math.pow(1 - progress, 4);
|
||||
const current = Math.round(target * easeOutQuart);
|
||||
|
||||
stat.textContent = originalText.replace(/\d+/g, current.toLocaleString());
|
||||
|
||||
if (frame === totalFrames) {
|
||||
clearInterval(counter);
|
||||
stat.textContent = originalText; // 恢复原始文本(包含符号)
|
||||
}
|
||||
}, frameDuration);
|
||||
});
|
||||
}
|
||||
|
||||
// 平滑滚动到锚点
|
||||
function smoothScrollTo(targetId) {
|
||||
const targetElement = document.querySelector(targetId);
|
||||
if (targetElement) {
|
||||
const offsetTop = targetElement.offsetTop - 80; // 考虑固定导航栏的高度
|
||||
|
||||
window.scrollTo({
|
||||
top: offsetTop,
|
||||
behavior: 'smooth'
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 导航链接点击事件
|
||||
document.querySelectorAll('a[href^="#"]').forEach(function(anchor) {
|
||||
anchor.addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const targetId = this.getAttribute('href');
|
||||
if (targetId !== '#') {
|
||||
smoothScrollTo(targetId);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// 响应式导航菜单关闭
|
||||
function closeMobileMenu() {
|
||||
const navbarToggler = document.querySelector('.navbar-toggler');
|
||||
const navbarCollapse = document.querySelector('.navbar-collapse');
|
||||
|
||||
if (navbarToggler && navbarCollapse.classList.contains('show')) {
|
||||
navbarToggler.click();
|
||||
}
|
||||
}
|
||||
|
||||
// 页面性能监控(可选)
|
||||
function monitorPerformance() {
|
||||
if ('performance' in window) {
|
||||
window.addEventListener('load', function() {
|
||||
const navigationTiming = performance.getEntriesByType('navigation')[0];
|
||||
console.log('页面加载时间:', navigationTiming.loadEventEnd - navigationTiming.navigationStart, 'ms');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 错误处理
|
||||
window.addEventListener('error', function(e) {
|
||||
console.error('页面错误:', e.error);
|
||||
});
|
||||
|
||||
// 初始化性能监控
|
||||
monitorPerformance();
|
||||
Reference in New Issue
Block a user