// index.js (改进版) // 功能: // 1. 解决用户列表竖向轮播在无缝跳转时出现的卡顿/闪动问题 // 2. 为每条拼单信息增加实时倒计时,秒级更新 document.addEventListener('DOMContentLoaded', function () { /* ---------- 顶部横向轮播 ---------- */ const wrapper = document.querySelector('.swiper-wrapper'); const slides = [...wrapper.children]; const pagination = document.querySelector('.swiper-pagination'); const count = slides.length; let current = 0; // 当前索引 let startX = 0; // 手势起点 let dragging = false; // 拖动状态 let timer = null; // 自动轮播计时器 /* --- 1. 生成分页小圆点 --- */ for(let i=0;igoTo(i)); pagination.appendChild(dot); } const dots = pagination.children; /* --- 2. 切换核心 --- */ function goTo(index){ current = (index + count) % count; // 防越界 wrapper.style.transition = 'transform .3s ease'; wrapper.style.transform = `translateX(-${current*100}%)`; [...dots].forEach((d,i)=>d.classList.toggle('active',i===current)); } /* --- 3. 自动轮播 --- */ function startAuto(){ timer = setInterval(()=>goTo(current+1),3000); } function stopAuto(){ clearInterval(timer); } startAuto(); /* --- 4. 手势/鼠标拖动 --- */ const getX = e => e.touches ? e.touches[0].clientX : e.clientX; wrapper.addEventListener('pointerdown',e=>{ stopAuto(); dragging = true; startX = getX(e); wrapper.style.transition = 'none'; // 跟手拖动 }); wrapper.addEventListener('pointermove',e=>{ if(!dragging) return; const diff = getX(e) - startX; // 像素位移 wrapper.style.transform = `translateX(calc(${-current*100}% + ${diff}px))`; }); const endSwipe = e=>{ if(!dragging) return; dragging = false; const diff = getX(e) - startX; const limit = wrapper.offsetWidth * 0.15; // 15% 宽度阈值 if(diff > limit) goTo(current-1); else if(diff < -limit) goTo(current+1); else goTo(current); // 回弹 startAuto(); }; wrapper.addEventListener('pointerup', endSwipe); wrapper.addEventListener('pointercancel', endSwipe); wrapper.addEventListener('pointerleave', endSwipe); /* --------- 动态生成“xx人在抢,参与可立即拼成” --------- */ const leftNum = Math.floor(Math.random() * 101) + 100; // 100 ~ 200 之间的随机整数 const leftSpan = document.querySelector('.group-left'); if (leftSpan) leftSpan.textContent = `${leftNum}人在抢,参与可立即拼成`; /* ---------- 拼单用户纵向轮播 ---------- */ const userList = document.getElementById('userList'); const userItems = userList.querySelectorAll('.user-item'); const itemHeight = userItems[0].offsetHeight; let userIndex = 0; const originalCount = userItems.length; // 克隆第一条放到末尾,实现无缝衔接 userList.appendChild(userItems[0].cloneNode(true)); userList.addEventListener('transitionend', () => { if (userIndex >= originalCount) { // 闪电跳回首条,关闭过渡以避免闪屏 userList.style.transition = 'none'; userList.style.transform = 'translateY(0)'; userIndex = 0; // 强制回流,保证下次 transition 生效 void userList.offsetWidth; } }); function rotateUsers() { userIndex++; userList.style.transition = 'transform 0.5s ease'; userList.style.transform = `translateY(${-userIndex * itemHeight}px)`; } // 每 3 秒滚动一次 setInterval(rotateUsers, 3000); // 页面加载后立即滚动一次,保证视觉一致 rotateUsers(); /* ---------- 拼单倒计时 ---------- */ const countdownEls = document.querySelectorAll('.countdown'); // 预处理:把初始文本转为秒数 const countdownData = Array.from(countdownEls).map((el) => ({ el, remain: parseTime(el.textContent.trim()), })); function parseTime(t) { const [h = '00', m = '00', s = '00'] = t.split(':'); return Number(h) * 3600 + Number(m) * 60 + Number(s); } function formatTime(sec) { const h = String(Math.floor(sec / 3600)).padStart(2, '0'); const m = String(Math.floor((sec % 3600) / 60)).padStart(2, '0'); const s = String(sec % 60).padStart(2, '0'); return `${h}:${m}:${s}`; } function updateCountdown() { countdownData.forEach((c) => { if (c.remain > 0) { c.remain -= 1; c.el.textContent = formatTime(c.remain); } else { c.el.textContent = '00:00:00'; // 可选:到点后给整条加灰色样式,并禁用按钮 const item = c.el.closest('.user-item'); item?.classList.add('expired'); item?.querySelector('.buy-btn')?.setAttribute('disabled', 'disabled'); } }); } /* --------- 给每条拼单状态前加 “仅剩 x 人成团” --------- */ document.querySelectorAll('.user-status').forEach(statusEl=>{ const x = Math.floor(Math.random()*3)+1; // 1 ~ 3 随机整数 const span = document.createElement('span'); span.className = 'left-num'; span.textContent = `仅剩${x}人成团,`; // 注意带逗号或空格 statusEl.prepend(span); }); /* ============= 支付 & 登录判断 ============= */ const modal = document.getElementById('paymentModal'); const paymentAmount = document.getElementById('paymentAmount'); const cancelPayment = document.getElementById('cancelPayment'); const completePayment= document.getElementById('completePayment'); /* 把 3 类按钮统一选出来 */ [...document.querySelectorAll('.buy-btn, .btn-single, .btn-group')].forEach(btn=>{ btn.addEventListener('click',()=>{ /* 简单读取 cookie 判断是否登录 */ if(!getCookie('username')){ window.location.href='login.html'; // 跳转到登录页 return; } /* 已登录:弹出支付弹窗 */ const price = btn.dataset.price || '0'; paymentAmount.textContent = `支付金额 ¥${price}`; modal.style.display='flex'; }); }); /* 取消/完成支付 */ cancelPayment.addEventListener('click', ()=>modal.style.display='none'); completePayment.addEventListener('click', ()=>{ alert('支付成功!'); modal.style.display='none'; }); /* 读取 cookie 工具函数 */ function getCookie(name){ return document.cookie.split(';').map(c=>c.trim()) .find(c=>c.startsWith(name+'='))?.split('=')[1] || null; } /* 点击遮罩空白关闭弹窗 */ modal.addEventListener('click', e=>{ if(e.target===modal) modal.style.display='none'; }); // 每秒刷新一次倒计时 setInterval(updateCountdown, 1000); });