199 lines
7.4 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.

// 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;i<count;i++){
const dot = document.createElement('div');
dot.className = 'swiper-dot' + (i===0?' active':'');
dot.addEventListener('click',()=>goTo(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);
});