✏️ 正在编辑: script.js
路径:
/var/www/koruspay.com.br-bkp/assets/js/script.js
提示:
您可以编辑任何文件(包括二进制文件),但请注意不当修改可能导致文件损坏。
// ===== MOBILE NAVIGATION ===== const navToggle = document.getElementById('nav-toggle'); const navMenu = document.getElementById('nav-menu'); const navClose = document.getElementById('nav-close'); const navLinks = document.querySelectorAll('.nav__link'); // Show menu if (navToggle) { navToggle.addEventListener('click', () => { navMenu.classList.add('show'); }); } // Hide menu if (navClose) { navClose.addEventListener('click', () => { navMenu.classList.remove('show'); }); } // Hide menu when clicking on nav links navLinks.forEach(link => { link.addEventListener('click', () => { navMenu.classList.remove('show'); }); }); // ===== HEADER SCROLL EFFECT ===== const header = document.querySelector('.header'); window.addEventListener('scroll', () => { if (window.scrollY >= 50) { header.style.background = '#1a1a4a'; header.style.boxShadow = '0 2px 20px rgba(0, 0, 0, 0.1)'; } else { header.style.background = '#1a1a4a'; header.style.boxShadow = 'none'; } }); // ===== SMOOTH SCROLLING ===== document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function (e) { e.preventDefault(); const target = document.querySelector(this.getAttribute('href')); if (target) { const headerHeight = header.offsetHeight; const targetPosition = target.offsetTop - headerHeight; window.scrollTo({ top: targetPosition, behavior: 'smooth' }); } }); }); // ===== FAQ ACCORDION ===== const faqItems = document.querySelectorAll('.faq__item'); faqItems.forEach(item => { const question = item.querySelector('.faq__question'); question.addEventListener('click', () => { const isActive = item.classList.contains('active'); // Close all FAQ items faqItems.forEach(faqItem => { faqItem.classList.remove('active'); }); // Open clicked item if it wasn't active if (!isActive) { item.classList.add('active'); } }); }); // ===== FORM HANDLING ===== const contactForm = document.querySelector('.contact__form'); if (contactForm) { contactForm.addEventListener('submit', function(e) { e.preventDefault(); // Get form data const formData = new FormData(this); const data = Object.fromEntries(formData); // Simple validation if (!data.name || !data.email || !data.company || !data.phone) { showNotification('Por favor, preencha todos os campos obrigatórios.', 'error'); return; } if (!isValidEmail(data.email)) { showNotification('Por favor, insira um email válido.', 'error'); return; } const submitButton = this.querySelector('button[type="submit"]'); const originalText = submitButton.innerHTML; submitButton.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Enviando...'; submitButton.disabled = true; result = callBackendExecution("src/contact_send.php", 'contact_form') .then(response => { if (response == 1) { showNotification('Mensagem enviada com sucesso! Entraremos em contato em breve.', 'success'); } else { showNotification(response, 'error'); } }) .catch(error => { showNotification(error, 'error'); }); setTimeout(() => { this.reset(); submitButton.innerHTML = originalText; submitButton.disabled = false; }, 2000); }); } // ===== EMAIL VALIDATION ===== function isValidEmail(email) { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; return emailRegex.test(email); } // ===== NOTIFICATION SYSTEM ===== function showNotification(message, type = 'info') { // Remove existing notifications const existingNotifications = document.querySelectorAll('.notification'); existingNotifications.forEach(notification => notification.remove()); // Create notification element const notification = document.createElement('div'); notification.className = `notification notification--${type}`; notification.innerHTML = ` <div class="notification__content"> <i class="fas ${getNotificationIcon(type)}"></i> <span>${message}</span> <button class="notification__close"> <i class="fas fa-times"></i> </button> </div> `; // Add styles notification.style.cssText = ` position: fixed; top: 100px; right: 20px; background: ${getNotificationColor(type)}; color: white; padding: 1rem 1.5rem; border-radius: 0.75rem; box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2); z-index: 10000; transform: translateX(400px); transition: transform 0.3s ease-in-out; max-width: 400px; `; notification.querySelector('.notification__content').style.cssText = ` display: flex; align-items: center; gap: 0.75rem; `; notification.querySelector('.notification__close').style.cssText = ` background: none; border: none; color: white; cursor: pointer; padding: 0; margin-left: auto; `; // Add to page document.body.appendChild(notification); // Animate in setTimeout(() => { notification.style.transform = 'translateX(0)'; }, 100); // Auto remove after 5 seconds setTimeout(() => { removeNotification(notification); }, 5000); // Close button functionality notification.querySelector('.notification__close').addEventListener('click', () => { removeNotification(notification); }); } function removeNotification(notification) { notification.style.transform = 'translateX(400px)'; setTimeout(() => { if (notification.parentNode) { notification.parentNode.removeChild(notification); } }, 300); } function getNotificationIcon(type) { switch (type) { case 'success': return 'fa-check-circle'; case 'error': return 'fa-exclamation-circle'; case 'warning': return 'fa-exclamation-triangle'; default: return 'fa-info-circle'; } } function getNotificationColor(type) { switch (type) { case 'success': return '#28a745'; case 'error': return '#dc3545'; case 'warning': return '#ffc107'; default: return '#17a2b8'; } } // ===== SCROLL ANIMATIONS ===== const observerOptions = { threshold: 0.1, rootMargin: '0px 0px -50px 0px' }; const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { entry.target.style.opacity = '1'; entry.target.style.transform = 'translateY(0)'; } }); }, observerOptions); // Observe elements for animation document.addEventListener('DOMContentLoaded', () => { const animateElements = document.querySelectorAll('.solution__card, .benefit__item, .stat__item, .pricing__card'); animateElements.forEach(el => { el.style.opacity = '0'; el.style.transform = 'translateY(30px)'; el.style.transition = 'opacity 0.6s ease-out, transform 0.6s ease-out'; observer.observe(el); }); }); // ===== COUNTER ANIMATION ===== function animateCounter(element, target, duration = 2000) { let start = 0; const increment = target / (duration / 16); const timer = setInterval(() => { start += increment; if (start >= target) { element.textContent = formatNumber(target); clearInterval(timer); } else { element.textContent = formatNumber(Math.floor(start)); } }, 16); } function formatNumber(num) { if (num >= 1000000000) { return (num / 1000000000).toFixed(1) + 'B'; } else if (num >= 1000000) { return (num / 1000000).toFixed(1) + 'M'; } else if (num >= 1000) { return (num / 1000).toFixed(1) + 'K'; } return num.toString(); } // Animate counters when stats section is visible const statsSection = document.querySelector('.stats'); let statsAnimated = false; if (statsSection) { const statsObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting && !statsAnimated) { statsAnimated = true; // Animate each counter const counters = [ { element: document.querySelector('.stat__item:nth-child(1) .stat__number'), target: 10000 }, { element: document.querySelector('.stat__item:nth-child(2) .stat__number'), target: 2000000000 }, { element: document.querySelector('.stat__item:nth-child(3) .stat__number'), target: 99.9 }, { element: document.querySelector('.stat__item:nth-child(4) .stat__number'), target: 24 } ]; counters.forEach((counter, index) => { if (counter.element) { setTimeout(() => { if (index === 2) { // Special handling for percentage let start = 0; const timer = setInterval(() => { start += 0.1; if (start >= 99.9) { counter.element.textContent = '99.9%'; clearInterval(timer); } else { counter.element.textContent = start.toFixed(1) + '%'; } }, 20); } else if (index === 3) { // Special handling for 24/7 counter.element.textContent = '24/7'; } else { animateCounter(counter.element, counter.target); } }, index * 200); } }); } }); }, { threshold: 0.5 }); statsObserver.observe(statsSection); } // ===== FLOATING CARDS ANIMATION ===== document.addEventListener('DOMContentLoaded', () => { const floatingCards = document.querySelectorAll('.hero__floating-card'); floatingCards.forEach((card, index) => { // Add mouse interaction card.addEventListener('mouseenter', () => { card.style.transform = 'translateY(-15px) scale(1.05)'; card.style.boxShadow = '0 20px 40px rgba(0, 0, 0, 0.2)'; }); card.addEventListener('mouseleave', () => { card.style.transform = 'translateY(0) scale(1)'; card.style.boxShadow = '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)'; }); }); }); // ===== PRICING CARD INTERACTIONS ===== document.addEventListener('DOMContentLoaded', () => { const pricingCards = document.querySelectorAll('.pricing__card'); pricingCards.forEach(card => { card.addEventListener('mouseenter', () => { if (!card.classList.contains('pricing__card--featured')) { card.style.borderColor = 'var(--secondary-color)'; } }); card.addEventListener('mouseleave', () => { if (!card.classList.contains('pricing__card--featured')) { card.style.borderColor = 'var(--gray-200)'; } }); }); }); // ===== LAZY LOADING FOR IMAGES ===== document.addEventListener('DOMContentLoaded', () => { const images = document.querySelectorAll('img[data-src]'); const imageObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; img.src = img.dataset.src; img.classList.remove('lazy'); imageObserver.unobserve(img); } }); }); images.forEach(img => imageObserver.observe(img)); }); // ===== PERFORMANCE OPTIMIZATION ===== // Debounce function for scroll events function debounce(func, wait) { let timeout; return function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; } // Optimized scroll handler const optimizedScrollHandler = debounce(() => { const scrollY = window.scrollY; // Header background change if (scrollY >= 50) { header.style.background = '#1a1a4a'; header.style.boxShadow = '0 2px 20px rgba(0, 0, 0, 0.1)'; } else { header.style.background = '#1a1a4a'; header.style.boxShadow = 'none'; } }, 10); // Replace the original scroll event listener window.removeEventListener('scroll', () => {}); window.addEventListener('scroll', optimizedScrollHandler); // ===== ACCESSIBILITY IMPROVEMENTS ===== document.addEventListener('DOMContentLoaded', () => { // Add keyboard navigation for FAQ faqItems.forEach(item => { const question = item.querySelector('.faq__question'); question.setAttribute('tabindex', '0'); question.setAttribute('role', 'button'); question.setAttribute('aria-expanded', 'false'); question.addEventListener('keydown', (e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); question.click(); } }); }); // Update aria-expanded for FAQ const originalFaqHandler = faqItems[0]?.querySelector('.faq__question')?.onclick; faqItems.forEach(item => { const question = item.querySelector('.faq__question'); question.addEventListener('click', () => { const isActive = item.classList.contains('active'); question.setAttribute('aria-expanded', isActive ? 'true' : 'false'); }); }); }); function callBackendExecution(scriptFile, formElement) { return new Promise((resolve, reject) => { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function() { if (this.readyState == 4 && this.status == 200) { resolve(this.responseText); } }; myForm = document.getElementById(formElement); // Get your form element serializedForm = serializeForm(myForm); xhr.open("POST", scriptFile, true); xhr.onerror = function() { reject(new Error('Network error or request failed')); }; xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); xhr.send(serializedForm); }); } function serializeForm(formElement) { const formData = new FormData(formElement); const serializedData = {}; for (const [name, value] of formData.entries()) { // Handle multiple values for the same name (e.g., checkboxes, multi-select) if (serializedData.hasOwnProperty(name)) { if (!Array.isArray(serializedData[name])) { serializedData[name] = [serializedData[name]]; // Convert to array if not already } serializedData[name].push(value); } else { serializedData[name] = value; } } const queryString = Object.keys(serializedData).map(key => { return encodeURIComponent(key) + '=' + encodeURIComponent(serializedData[key]); }).join('&'); return queryString; }
💾 保存文件
← 返回文件管理器