Files
web_template/web/dist/shop4/index.html

1105 lines
52 KiB
HTML
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.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>古树商城 · TreeShop</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'><rect width='100' height='100' rx='20' fill='%231a1a2e'/><text x='50' y='68' font-size='50' fill='%2380d8' text-anchor='middle'>🌳</text></svg>">
<style>
*,*::before,*::after{margin:0;padding:0;box-sizing:border-box}
:root{
--bg:#0a0e0a;--bg2:#121810;--surface:rgba(255,255,255,.04);--card:rgba(255,255,255,.06);
--border:rgba(255,255,255,.08);--text:#e6edf3;--text-muted:#7d8590;
--primary:#58d68d;--primary-glow:rgba(88,214,141,.25);--accent:#f0c674;
--radius:16px;--blur-amount:8px;
}
[data-theme="light"]{
--bg:#f5f3f0;--bg2:#ffffff;--surface:rgba(0,0,0,.03);--card:rgba(0,0,0,.04);
--border:rgba(0,0,0,.08);--text:#1a1a2e;--text-muted:#6b7280;
--primary:#2d7a4e;--primary-glow:rgba(45,122,78,.2);--accent:#b8860b;
}
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Noto Sans SC,sans-serif;background:var(--bg);color:var(--text);overflow-x:hidden;transition:background .4s,color .4s}
a{color:inherit;text-decoration:none}
/* ========== 导航栏 ========== */
.navbar{position:fixed;top:0;left:0;right:0;z-index:200;display:flex;align-items:center;justify-content:space-between;padding:16px 32px;background:rgba(10,14,10,.6);backdrop-filter:blur(20px);border-bottom:1px solid var(--border);transition:all .4s}
[data-theme="light"] .navbar{background:rgba(255,255,255,.7)}
.nav-brand{font-size:22px;font-weight:800;display:flex;align-items:center;gap:8px}
.nav-brand .tree-icon{font-size:26px}
.nav-links{display:flex;gap:28px}
.nav-links a{font-size:14px;font-weight:500;color:var(--text-muted);transition:color .2s;cursor:pointer}
.nav-links a:hover{color:var(--text)}
.nav-actions{display:flex;align-items:center;gap:16px}
.cart-btn{position:relative;background:var(--surface);border:1px solid var(--border);border-radius:50%;width:40px;height:40px;display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:18px;color:var(--text)}
.cart-badge{position:absolute;top:-4px;right:-4px;background:var(--primary);color:#fff;font-size:11px;font-weight:700;min-width:18px;height:18px;border-radius:9px;display:flex;align-items:center;justify-content:center;padding:0 4px}
/* ========== 黑白模式切换 ========== */
.theme-toggle{position:relative;width:44px;height:44px;border-radius:50%;border:1px solid var(--border);background:var(--surface);cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .3s;overflow:hidden}
.theme-toggle:hover{border-color:var(--primary);box-shadow:0 0 16px var(--primary-glow)}
.theme-toggle .sun-icon{position:absolute;font-size:22px;transition:all .4s cubic-bezier(.4,0,.2,1)}
[data-theme="dark"] .sun-icon{transform:translateY(0) rotate(0);opacity:1}
[data-theme="light"] .sun-icon{transform:translateY(-40px) rotate(180deg);opacity:0}
.theme-toggle .moon-icon{position:absolute;font-size:20px;transition:all .4s cubic-bezier(.4,0,.2,1)}
[data-theme="dark"] .moon-icon{transform:translateY(40px) rotate(180deg);opacity:0}
[data-theme="light"] .moon-icon{transform:translateY(0) rotate(0);opacity:1}
/* ========== Hero 横向动态 ========== */
.hero{position:relative;width:100%;height:100vh;min-height:640px;overflow:hidden;background:#060a06}
#treeCanvas{position:absolute;inset:0;width:100%;height:100%;z-index:1}
.hero-overlay{position:absolute;inset:0;z-index:2;background:linear-gradient(180deg,rgba(6,10,6,.1) 0%,rgba(6,10,6,.35) 55%,var(--bg) 100%);pointer-events:none;transition:background .4s}
[data-theme="light"] .hero-overlay{background:linear-gradient(180deg,rgba(245,243,240,.05) 0%,rgba(245,243,240,.3) 55%,var(--bg) 100%)}
/* 横向滚动容器 */
.hero-scroll-wrap{position:absolute;inset:0;z-index:3;display:flex;align-items:center;overflow-x:auto;overflow-y:hidden;scroll-snap-type:x mandatory;scrollbar-width:none}
.hero-scroll-wrap::-webkit-scrollbar{display:none}
.hero-panel{min-width:100vw;height:100vh;display:flex;align-items:center;justify-content:center;scroll-snap-align:start;position:relative;padding:0 8vw}
.hero-panel-content{max-width:680px}
.hero-badge{display:inline-flex;align-items:center;gap:8px;padding:6px 18px;border-radius:100px;background:rgba(255,255,255,.06);border:1px solid rgba(255,255,255,.12);font-size:13px;color:rgba(255,255,255,.7);margin-bottom:24px;backdrop-filter:blur(10px)}
.hero-badge .dot{width:6px;height:6px;border-radius:50%;background:var(--primary);box-shadow:0 0 8px var(--primary);animation:pulse 2s infinite}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.3}}
.hero-panel h1{font-size:64px;font-weight:900;line-height:1.08;letter-spacing:-2px;color:#fff;margin-bottom:20px;text-shadow:0 4px 30px rgba(0,0,0,.5)}
[data-theme="light"] .hero-panel h1{color:#1a1a2e;text-shadow:0 4px 30px rgba(0,0,0,.1)}
.hero-panel h1 .accent{background:linear-gradient(135deg,var(--primary) 0%,var(--accent) 100%);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}
.hero-panel p{font-size:18px;color:rgba(255,255,255,.55);line-height:1.7;margin-bottom:32px;max-width:520px}
[data-theme="light"] .hero-panel p{color:rgba(26,26,46,.6)}
.hero-panel-actions{display:flex;gap:14px;align-items:center}
.btn-primary{display:inline-flex;align-items:center;gap:8px;background:linear-gradient(135deg,var(--primary),#3da56a);color:#fff;padding:14px 36px;border-radius:100px;font-size:15px;font-weight:700;border:none;cursor:pointer;transition:all .3s;box-shadow:0 8px 28px var(--primary-glow)}
.btn-primary:hover{transform:translateY(-2px);box-shadow:0 12px 36px var(--primary-glow)}
.btn-ghost{display:inline-flex;align-items:center;gap:8px;background:rgba(255,255,255,.06);color:#fff;padding:14px 28px;border-radius:100px;font-size:14px;font-weight:600;border:1px solid rgba(255,255,255,.15);cursor:pointer;backdrop-filter:blur(10px);transition:all .3s}
[data-theme="light"] .btn-ghost{color:#1a1a2e;background:rgba(0,0,0,.04);border-color:rgba(0,0,0,.1)}
.btn-ghost:hover{background:rgba(255,255,255,.12)}
[data-theme="light"] .btn-ghost:hover{background:rgba(0,0,0,.08)}
/* 横向指示器 */
.hero-dots{position:absolute;bottom:40px;left:50%;transform:translateX(-50%);z-index:5;display:flex;gap:10px}
.hero-dot{width:8px;height:8px;border-radius:50%;background:rgba(255,255,255,.2);cursor:pointer;transition:all .3s}
.hero-dot.active{width:28px;border-radius:4px;background:var(--primary)}
.hero-arrow{position:absolute;bottom:20px;right:40px;z-index:5;color:rgba(255,255,255,.4);font-size:12px;display:flex;align-items:center;gap:6px;animation:bounce-h 2s infinite}
@keyframes bounce-h{0%,100%{transform:translateX(0)}50%{transform:translateX(8px)}}
/* 面板2/3 样式 */
.hero-features{display:grid;grid-template-columns:repeat(2,1fr);gap:20px;margin-top:32px}
.hero-feature{background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.08);border-radius:var(--radius);padding:24px;backdrop-filter:blur(10px)}
[data-theme="light"] .hero-feature{background:rgba(0,0,0,.03);border-color:rgba(0,0,0,.06)}
.hero-feature .icon{font-size:32px;margin-bottom:12px}
.hero-feature h3{font-size:16px;font-weight:700;color:#fff;margin-bottom:6px}
[data-theme="light"] .hero-feature h3{color:#1a1a2e}
.hero-feature p{font-size:13px;color:rgba(255,255,255,.5);line-height:1.5}
[data-theme="light"] .hero-feature p{color:rgba(26,26,46,.55)}
/* ========== 商品表格区域 ========== */
.products-section{position:relative;min-height:100vh;padding:80px 0;z-index:10}
.products-bg{position:absolute;inset:0;z-index:0;overflow:hidden}
.products-bg canvas{width:100%;height:100%;display:block}
.products-bg::after{content:'';position:absolute;inset:0;background:var(--bg);opacity:.82}
.products-content{position:relative;z-index:1;max-width:1280px;margin:0 auto;padding:0 32px}
.section-header{text-align:center;margin-bottom:48px}
.section-header h2{font-size:36px;font-weight:800;letter-spacing:-1px;margin-bottom:12px}
.section-header h2 .accent{color:var(--primary)}
.section-header p{font-size:15px;color:var(--text-muted)}
/* 筛选条 */
.filter-bar{display:flex;gap:12px;align-items:center;flex-wrap:wrap;margin-bottom:32px;justify-content:center}
.filter-chip{padding:8px 20px;border-radius:100px;background:var(--surface);border:1px solid var(--border);font-size:13px;font-weight:500;color:var(--text-muted);cursor:pointer;transition:all .2s}
.filter-chip:hover{border-color:var(--primary);color:var(--text)}
.filter-chip.active{background:var(--primary);color:#fff;border-color:var(--primary)}
.search-box{display:flex;align-items:center;gap:8px;background:var(--surface);border:1px solid var(--border);border-radius:100px;padding:8px 20px;min-width:240px}
.search-box input{background:none;border:none;outline:none;color:var(--text);font-size:14px;flex:1}
.search-box svg{width:16px;height:16px;color:var(--text-muted)}
/* 表格 */
.table-wrap{background:var(--bg2);border-radius:var(--radius);overflow:hidden;border:1px solid var(--border);box-shadow:0 8px 32px rgba(0,0,0,.15)}
.product-table{width:100%;border-collapse:collapse}
.product-table th{background:var(--surface);padding:16px 20px;text-align:left;font-size:13px;font-weight:700;color:var(--text-muted);text-transform:uppercase;letter-spacing:.5px;border-bottom:1px solid var(--border);white-space:nowrap}
.product-table td{padding:14px 20px;border-bottom:1px solid var(--border);font-size:14px;vertical-align:middle}
.product-table tbody tr{transition:background .2s;cursor:pointer}
.product-table tbody tr:hover{background:var(--surface)}
.product-table tbody tr:last-child td{border-bottom:none}
.td-img{width:60px;height:60px;border-radius:10px;overflow:hidden;display:flex;align-items:center;justify-content:center;flex-shrink:0}
.td-img img{width:100%;height:100%;object-fit:cover}
.td-img .placeholder{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:24px;background:var(--surface)}
.td-name{font-weight:600;color:var(--text)}
.td-price{font-weight:700;color:var(--primary);font-size:15px}
.td-category{color:var(--text-muted);font-size:13px}
.td-rating{display:flex;align-items:center;gap:4px}
.td-rating .star{color:var(--accent)}
.td-actions{display:flex;gap:8px}
.td-btn{padding:6px 16px;border-radius:8px;font-size:12px;font-weight:600;border:none;cursor:pointer;transition:all .2s}
.td-btn-primary{background:var(--primary);color:#fff}
.td-btn-primary:hover{opacity:.85}
.td-btn-ghost{background:var(--surface);color:var(--text);border:1px solid var(--border)}
.td-btn-ghost:hover{border-color:var(--primary)}
/* 分页 */
.pagination{display:flex;gap:8px;justify-content:center;align-items:center;margin-top:32px}
.page-btn{min-width:40px;height:40px;border-radius:10px;border:1px solid var(--border);background:var(--surface);color:var(--text-muted);font-size:14px;font-weight:600;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all .2s}
.page-btn:hover:not(:disabled){border-color:var(--primary);color:var(--text)}
.page-btn.active{background:var(--primary);color:#fff;border-color:var(--primary)}
.page-btn:disabled{opacity:.4;cursor:not-allowed}
/* ========== Footer ========== */
.footer{background:var(--bg2);border-top:1px solid var(--border);padding:48px 32px 32px}
.footer-content{max-width:1280px;margin:0 auto;display:grid;grid-template-columns:2fr 1fr 1fr 1fr;gap:40px}
.footer-brand h3{font-size:20px;font-weight:800;margin-bottom:12px;display:flex;align-items:center;gap:8px}
.footer-brand p{font-size:13px;color:var(--text-muted);line-height:1.6;max-width:320px}
.footer-col h4{font-size:14px;font-weight:700;margin-bottom:14px}
.footer-col a{display:block;font-size:13px;color:var(--text-muted);padding:4px 0;cursor:pointer;transition:color .2s}
.footer-col a:hover{color:var(--text)}
.footer-bottom{text-align:center;padding:24px 0 0;margin-top:32px;border-top:1px solid var(--border);font-size:12px;color:var(--text-muted)}
/* ========== Modal ========== */
.modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,.6);backdrop-filter:blur(8px);z-index:300;display:none;align-items:center;justify-content:center;padding:24px}
.modal-overlay.active{display:flex}
.modal{background:var(--bg2);border-radius:var(--radius);max-width:640px;width:100%;max-height:85vh;overflow-y:auto;border:1px solid var(--border)}
.modal-header{display:flex;align-items:center;justify-content:space-between;padding:24px;border-bottom:1px solid var(--border)}
.modal-header h3{font-size:20px;font-weight:700}
.modal-close{background:var(--surface);border:1px solid var(--border);border-radius:50%;width:36px;height:36px;display:flex;align-items:center;justify-content:center;cursor:pointer;font-size:18px;color:var(--text)}
.modal-body{padding:24px}
.modal-body img{width:100%;border-radius:12px;margin-bottom:16px}
.modal-info{display:grid;grid-template-columns:1fr 1fr;gap:16px;margin-bottom:16px}
.modal-info-item{font-size:13px}
.modal-info-item .label{color:var(--text-muted);margin-bottom:2px}
.modal-info-item .value{font-weight:600}
.modal-desc{font-size:14px;line-height:1.6;color:var(--text-muted);margin-bottom:20px}
.modal-actions{display:flex;gap:12px}
/* Toast */
.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%) translateY(-20px);background:var(--bg2);border:1px solid var(--primary);border-radius:12px;padding:12px 24px;font-size:14px;font-weight:600;z-index:400;opacity:0;transition:all .3s;pointer-events:none}
.toast.show{opacity:1;transform:translateX(-50%) translateY(0)}
/* Cart drawer */
.cart-overlay{position:fixed;inset:0;background:rgba(0,0,0,.5);z-index:280;display:none}
.cart-overlay.active{display:block}
.cart-drawer{position:fixed;top:0;right:0;width:400px;max-width:90vw;height:100vh;background:var(--bg2);border-left:1px solid var(--border);z-index:290;transform:translateX(100%);transition:transform .3s;display:flex;flex-direction:column}
.cart-drawer.active{transform:translateX(0)}
.cart-drawer-header{padding:20px 24px;border-bottom:1px solid var(--border);display:flex;align-items:center;justify-content:space-between}
.cart-drawer-header h3{font-size:18px;font-weight:700}
.cart-items{flex:1;overflow-y:auto;padding:16px 24px}
.cart-item{display:flex;gap:12px;padding:12px 0;border-bottom:1px solid var(--border)}
.cart-item-img{width:50px;height:50px;border-radius:8px;overflow:hidden;background:var(--surface);display:flex;align-items:center;justify-content:center;font-size:20px;flex-shrink:0}
.cart-item-img img{width:100%;height:100%;object-fit:cover}
.cart-item-info{flex:1}
.cart-item-name{font-size:14px;font-weight:600;margin-bottom:2px}
.cart-item-price{font-size:13px;color:var(--primary);font-weight:700}
.cart-item-qty{display:flex;align-items:center;gap:8px;margin-top:4px}
.qty-btn{width:24px;height:24px;border-radius:6px;border:1px solid var(--border);background:var(--surface);cursor:pointer;color:var(--text);font-size:14px}
.cart-empty{text-align:center;padding:40px 0;color:var(--text-muted)}
.cart-drawer-footer{padding:20px 24px;border-top:1px solid var(--border)}
.cart-total{display:flex;justify-content:space-between;margin-bottom:16px;font-size:16px;font-weight:700}
.cart-total .price{color:var(--primary)}
.checkout-btn{width:100%;padding:14px;border-radius:12px;background:var(--primary);color:#fff;font-size:15px;font-weight:700;border:none;cursor:pointer;transition:opacity .2s}
.checkout-btn:hover{opacity:.85}
.checkout-btn:disabled{opacity:.4;cursor:not-allowed}
/* Responsive */
@media(max-width:768px){
.hero-panel h1{font-size:36px}
.hero-features{grid-template-columns:1fr}
.footer-content{grid-template-columns:1fr 1fr}
.nav-links{display:none}
.product-table{font-size:12px}
.product-table th,.product-table td{padding:10px 12px}
.td-img{width:40px;height:40px}
}
</style>
</head>
<body data-theme="dark">
<!-- 导航栏 -->
<nav class="navbar">
<div class="nav-brand"><span class="tree-icon">🌳</span> TreeShop</div>
<div class="nav-links">
<a onclick="scrollToProducts()">全部商品</a>
<a onclick="scrollToProducts()">分类</a>
<a onclick="showToast('关于我们')">关于</a>
<a onclick="showToast('联系方式')">联系</a>
</div>
<div class="nav-actions">
<button class="theme-toggle" onclick="toggleTheme()" title="切换黑白模式">
<span class="sun-icon">☀️</span>
<span class="moon-icon">🌙</span>
</button>
<button class="cart-btn" onclick="toggleCart()">
🛒 <span class="cart-badge" id="cartBadge" style="display:none">0</span>
</button>
</div>
</nav>
<!-- Hero 横向动态 -->
<div class="hero">
<canvas id="treeCanvas"></canvas>
<div class="hero-overlay"></div>
<div class="hero-scroll-wrap" id="heroScroll">
<!-- 面板1 -->
<div class="hero-panel">
<div class="hero-panel-content">
<div class="hero-badge"><span class="dot"></span> 古树商城 · 2026 新季</div>
<h1>扎根全球<br><span class="accent">枝连万物</span></h1>
<p>如古树般扎根品质,如枝叶般连接全球好物。精选电子工具品类,从榨汁机到搅拌机,每一件产品都经过严选,为您带来高效纯粹的厨房体验。</p>
<div class="hero-panel-actions">
<button class="btn-primary" onclick="scrollToProducts()">
探索商品
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="width:18px;height:18px"><path d="M5 12h14M12 5l7 7-7 7"/></svg>
</button>
<button class="btn-ghost" onclick="scrollToPanel(1)">了解更多 →</button>
</div>
</div>
</div>
<!-- 面板2 -->
<div class="hero-panel">
<div class="hero-panel-content">
<div class="hero-badge"><span class="dot"></span> 品质承诺</div>
<h1>四大根基<br><span class="accent">品质如树</span></h1>
<div class="hero-features">
<div class="hero-feature"><div class="icon">🌍</div><h3>全球直邮</h3><p>满 $99 免运费,覆盖全球 200+ 国家和地区</p></div>
<div class="hero-feature"><div class="icon">✅</div><h3>正品保障</h3><p>品牌授权直供,假一赔十承诺</p></div>
<div class="hero-feature"><div class="icon">🔄</div><h3>7天退换</h3><p>无理由退货,购物零风险</p></div>
<div class="hero-feature"><div class="icon">🔒</div><h3>安全支付</h3><p>多渠道加密,保障支付安全</p></div>
</div>
<div class="hero-panel-actions" style="margin-top:32px">
<button class="btn-primary" onclick="scrollToProducts()">浏览商品</button>
<button class="btn-ghost" onclick="scrollToPanel(0)">← 返回</button>
</div>
</div>
</div>
<!-- 面板3 -->
<div class="hero-panel">
<div class="hero-panel-content" style="text-align:center">
<div class="hero-badge" style="margin:0 auto 24px"><span class="dot"></span> 数据一览</div>
<h1 style="text-align:center">数字见证<br><span class="accent">用户信赖</span></h1>
<div class="hero-features" style="grid-template-columns:repeat(4,1fr);margin-top:40px">
<div class="hero-feature" style="text-align:center"><div class="icon">📦</div><h3 style="font-size:28px;color:var(--primary)">18+</h3><p>品类好物</p></div>
<div class="hero-feature" style="text-align:center"><div class="icon">👥</div><h3 style="font-size:28px;color:var(--primary)">50万</h3><p>全球用户</p></div>
<div class="hero-feature" style="text-align:center"><div class="icon">⭐</div><h3 style="font-size:28px;color:var(--primary)">99%</h3><p>好评率</p></div>
<div class="hero-feature" style="text-align:center"><div class="icon">🌿</div><h3 style="font-size:28px;color:var(--primary)">7天</h3><p>无理由退换</p></div>
</div>
<div class="hero-panel-actions" style="margin-top:32px;justify-content:center">
<button class="btn-primary" onclick="scrollToProducts()">立即选购</button>
</div>
</div>
</div>
</div>
<div class="hero-dots" id="heroDots">
<div class="hero-dot active" onclick="scrollToPanel(0)"></div>
<div class="hero-dot" onclick="scrollToPanel(1)"></div>
<div class="hero-dot" onclick="scrollToPanel(2)"></div>
</div>
<div class="hero-arrow">横向滚动 →</div>
</div>
<!-- 商品表格区域 -->
<div class="products-section" id="productsSection">
<div class="products-bg" id="productsBg"></div>
<div class="products-content">
<div class="section-header">
<h2>电子工具<span class="accent">精选</span></h2>
<p>高效厨房好物,品质如树,扎根全球</p>
</div>
<div class="filter-bar" id="filterBar">
<button class="filter-chip active" data-cat="0" onclick="filterCategory(0,this)">全部分类</button>
<button class="filter-chip" data-cat="1" onclick="filterCategory(1,this)">榨汁搅拌</button>
<button class="filter-chip" data-cat="2" onclick="filterCategory(2,this)">烹饪烘焙</button>
<button class="filter-chip" data-cat="3" onclick="filterCategory(3,this)">生活电器</button>
<div class="search-box">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/></svg>
<input type="text" id="searchInput" placeholder="搜索商品..." oninput="onSearch()">
</div>
</div>
<div class="table-wrap">
<table class="product-table">
<thead>
<tr>
<th>图片</th>
<th>商品名称</th>
<th>分类</th>
<th>价格</th>
<th>评分</th>
<th>销量</th>
<th>操作</th>
</tr>
</thead>
<tbody id="productTbody"></tbody>
</table>
</div>
<div class="pagination" id="pagination"></div>
</div>
</div>
<!-- Footer -->
<footer class="footer">
<div class="footer-content">
<div class="footer-brand">
<h3>🌳 TreeShop</h3>
<p>如古树般扎根品质,如枝叶般连接全球。精选电子工具好物,为您带来高效纯粹的跨境购物体验。</p>
</div>
<div class="footer-col">
<h4>购物指南</h4>
<a>购物流程</a><a>会员介绍</a><a>常见问题</a><a>联系客服</a>
</div>
<div class="footer-col">
<h4>配送退换</h4>
<a>配送方式</a><a>运费规则</a><a>退换货政策</a><a>退款说明</a>
</div>
<div class="footer-col">
<h4>关于我们</h4>
<a>公司简介</a><a>加入我们</a><a>隐私政策</a><a>用户协议</a>
</div>
</div>
<div class="footer-bottom">© 2026 TreeShop · 古树商城 · 电子工具精选</div>
</footer>
<!-- Cart -->
<div class="cart-overlay" id="cartOverlay" onclick="toggleCart()"></div>
<div class="cart-drawer" id="cartDrawer">
<div class="cart-drawer-header">
<h3>购物车</h3>
<button class="modal-close" onclick="toggleCart()">×</button>
</div>
<div class="cart-items" id="cartItems"></div>
<div class="cart-drawer-footer">
<div class="cart-total"><span>合计</span><span class="price" id="cartTotal">$0</span></div>
<button class="checkout-btn" id="checkoutBtn" disabled onclick="showToast('结算功能开发中')">去结算</button>
</div>
</div>
<!-- Modal -->
<div class="modal-overlay" id="modalOverlay" onclick="if(event.target===this)closeModal()">
<div class="modal" id="modal"></div>
</div>
<!-- Toast -->
<div class="toast" id="toast"><span id="toastMsg"></span></div>
<script>
// ========== 全局状态 ==========
var currentPage = 1, pageSize = 10, totalPages = 1, currentCat = 0, searchKey = '';
var cart = [];
// ========== 电子工具商品数据 ==========
var allProducts = [
{ id:1, name:'冷压慢速榨汁机 Pro Max', cat:1, catName:'榨汁搅拌', price:189.99, rating:4.9, sales:12800, icon:'🥤', desc:'采用冷压慢速技术,保留90%以上营养。75mm大口径整果压榨,无需切块。陶瓷螺旋杆,果汁更细腻。' },
{ id:2, name:'多功能破壁料理机 1200W', cat:1, catName:'榨汁搅拌', price:159.99, rating:4.8, sales:9600, icon:'🌀', desc:'8叶精钢刀片,38000转/分钟高速破壁。冷热双杯配置,一机多用,支持豆浆、浓汤、冰沙。' },
{ id:3, name:'便携式电动榨汁杯 USB充电', cat:1, catName:'榨汁搅拌', price:39.99, rating:4.6, sales:35000, icon:'🔋', desc:'口袋便携设计,USB充电续航30次。6叶刀头强力搅拌,30秒出汁, Tritan材质安全无忧。' },
{ id:4, name:'手持搅拌棒 700W 免拆洗', cat:1, catName:'榨汁搅拌', price:69.99, rating:4.7, sales:21000, icon:'✋', desc:'700W大功率,一键拆卸。不锈钢刀头防锈耐用,配备打蛋器和量杯配件。' },
{ id:5, name:'空气炸锅 5.5L 无油低脂', cat:2, catName:'烹饪烘焙', price:119.99, rating:4.8, sales:18500, icon:'🍟', desc:'360°热风循环,无需翻面。5.5L大容量满足全家需求。8大预设菜单,触控操作一键烹饪。' },
{ id:6, name:'智能电烤箱 32L 风炉发酵', cat:2, catName:'烹饪烘焙', price:229.99, rating:4.7, sales:7800, icon:'🔥', desc:'上下管独立控温,风炉均匀烘烤。内置发酵功能,360°旋转烤叉。搪瓷内胆易清洁。' },
{ id:7, name:'全自动咖啡机 15Bar 浓缩', cat:2, catName:'烹饪烘焙', price:299.99, rating:4.9, sales:5600, icon:'☕', desc:'15Bar压力萃取,奶泡一体。PID温控精准±1°C。豆粉双用,支持自定义杯量和浓度。' },
{ id:8, name:'多功能厨师机 1000W 和面', cat:2, catName:'烹饪烘焙', price:259.99, rating:4.8, sales:6200, icon:'👨‍🍳', desc:'1000W大功率直流电机,10级调速。行星搅拌轨迹,配搅拌/打蛋/和面三配件。5.5L不锈钢盆。' },
{ id:9, name:'智能电饭煲 4L IH电磁加热', cat:3, catName:'生活电器', price:179.99, rating:4.9, sales:24000, icon:'🍚', desc:'IH电磁环绕加热,米饭粒粒分明。12大烹饪菜单,支持柴火饭、煲仔饭、蛋糕。APP远程控制。' },
{ id:10, name:'桌面冷风扇 遥控加湿', cat:3, catName:'生活电器', price:89.99, rating:4.5, sales:15000, icon:'❄️', desc:'三档风速,冰晶制冷快速降温。内置加湿功能,7L大水箱。远程遥控,定时12小时。' },
{ id:11, name:'破壁豆浆机 加热免滤', cat:1, catName:'榨汁搅拌', price:149.99, rating:4.7, sales:13000, icon:'🫘', desc:'加热免滤一体,干豆直接打。8叶刀头高速破壁,医用级304不锈钢内胆。防溢防糊双重保护。' },
{ id:12, name:'真空封口机 干湿两用', cat:3, catName:'生活电器', price:49.99, rating:4.6, sales:8900, icon:'📦', desc:'干湿双模式抽真空,保鲜延长5倍。一键操作,支持连续封口。附送10个真空袋。' }
];
// ========== 工具函数 ==========
function showToast(msg) {
var t = document.getElementById('toast');
document.getElementById('toastMsg').textContent = msg;
t.classList.add('show');
clearTimeout(window._tt);
window._tt = setTimeout(function(){ t.classList.remove('show'); }, 2500);
}
function fmtPrice(p) { return '$' + Number(p).toFixed(2); }
function starsHTML(r) {
var s = '';
for (var i = 0; i < 5; i++) s += i < Math.round(r) ? '<span class="star">★</span>' : '<span style="color:var(--text-muted)">★</span>';
return s;
}
function productImgHTML(p) {
return '<div class="placeholder">' + (p.icon || '🔌') + '</div>';
}
// ========== 黑白模式切换 ==========
function toggleTheme() {
var body = document.body;
var current = body.getAttribute('data-theme');
body.setAttribute('data-theme', current === 'dark' ? 'light' : 'dark');
showToast(current === 'dark' ? '已切换至明亮模式' : '已切换至暗黑模式');
}
// ========== Hero 横向滚动 ==========
function scrollToPanel(idx) {
document.getElementById('heroScroll').scrollTo({ left: idx * window.innerWidth, behavior: 'smooth' });
}
document.getElementById('heroScroll').addEventListener('scroll', function() {
var idx = Math.round(this.scrollLeft / window.innerWidth);
document.querySelectorAll('.hero-dot').forEach(function(d, i) { d.classList.toggle('active', i === idx); });
});
function scrollToProducts() {
document.getElementById('productsSection').scrollIntoView({ behavior: 'smooth' });
}
// ========== 商品加载(本地数据)==========
function getFilteredProducts() {
var list = allProducts;
if (currentCat > 0) list = list.filter(function(p){ return p.cat === currentCat; });
if (searchKey) {
var k = searchKey.toLowerCase();
list = list.filter(function(p){ return p.name.toLowerCase().indexOf(k) >= 0 || p.catName.indexOf(searchKey) >= 0; });
}
return list;
}
function loadProducts() {
var all = getFilteredProducts();
totalPages = Math.ceil(all.length / pageSize);
if (currentPage > totalPages) currentPage = 1;
var start = (currentPage - 1) * pageSize;
var list = all.slice(start, start + pageSize);
renderTable(list);
renderPagination();
}
function renderTable(list) {
var tbody = document.getElementById('productTbody');
if (!list.length) {
tbody.innerHTML = '<tr><td colspan="7" style="text-align:center;padding:48px;color:var(--text-muted)">暂无商品</td></tr>';
return;
}
tbody.innerHTML = list.map(function(p) {
return '<tr onclick="showDetail(' + p.id + ')">' +
'<td><div class="td-img">' + productImgHTML(p) + '</div></td>' +
'<td class="td-name">' + p.name + '</td>' +
'<td class="td-category">' + p.catName + '</td>' +
'<td class="td-price">' + fmtPrice(p.price) + '</td>' +
'<td><div class="td-rating">' + starsHTML(p.rating) + ' <span style="font-size:12px;color:var(--text-muted)">' + p.rating.toFixed(1) + '</span></div></td>' +
'<td style="color:var(--text-muted)">' + p.sales.toLocaleString() + '</td>' +
'<td><div class="td-actions" onclick="event.stopPropagation()">' +
'<button class="td-btn td-btn-primary" onclick="addToCart(' + p.id + ')">加购</button>' +
'<button class="td-btn td-btn-ghost" onclick="showDetail(' + p.id + ')">详情</button>' +
'</div></td>' +
'</tr>';
}).join('');
}
function renderPagination() {
var pag = document.getElementById('pagination');
var html = '<button class="page-btn" ' + (currentPage <= 1 ? 'disabled' : '') + ' onclick="goPage(' + (currentPage - 1) + ')">‹</button>';
for (var i = 1; i <= totalPages; i++) {
html += '<button class="page-btn ' + (i === currentPage ? 'active' : '') + '" onclick="goPage(' + i + ')">' + i + '</button>';
}
html += '<button class="page-btn" ' + (currentPage >= totalPages ? 'disabled' : '') + ' onclick="goPage(' + (currentPage + 1) + ')">›</button>';
pag.innerHTML = html;
}
function goPage(p) { currentPage = p; loadProducts(); }
function filterCategory(cat, el) {
currentCat = cat; currentPage = 1;
document.querySelectorAll('.filter-chip').forEach(function(c){ c.classList.remove('active'); });
el.classList.add('active');
loadProducts();
}
function onSearch() {
clearTimeout(window._st);
window._st = setTimeout(function() {
searchKey = document.getElementById('searchInput').value;
currentPage = 1;
loadProducts();
}, 380);
}
function showDetail(id) {
var p = allProducts.find(function(x){ return x.id === id; });
if (!p) return;
var modal = document.getElementById('modal');
modal.innerHTML =
'<div class="modal-header"><h3>' + p.name + '</h3><button class="modal-close" onclick="closeModal()">×</button></div>' +
'<div class="modal-body">' +
'<div style="width:100%;height:200px;border-radius:12px;margin-bottom:16px;display:flex;align-items:center;justify-content:center;font-size:72px;background:var(--surface)">' + (p.icon || '🔌') + '</div>' +
'<div class="modal-info">' +
'<div class="modal-info-item"><div class="label">分类</div><div class="value">' + p.catName + '</div></div>' +
'<div class="modal-info-item"><div class="label">价格</div><div class="value" style="color:var(--primary);font-size:18px">' + fmtPrice(p.price) + '</div></div>' +
'<div class="modal-info-item"><div class="label">评分</div><div class="value">' + starsHTML(p.rating) + ' ' + p.rating.toFixed(1) + '</div></div>' +
'<div class="modal-info-item"><div class="label">销量</div><div class="value">' + p.sales.toLocaleString() + ' 件</div></div>' +
'</div>' +
'<div class="modal-desc">' + p.desc + '</div>' +
'<div class="modal-actions">' +
'<button class="btn-primary" style="flex:1" onclick="addToCart(' + p.id + ');closeModal()">加入购物车</button>' +
'<button class="btn-ghost" onclick="closeModal()">关闭</button>' +
'</div>' +
'</div>';
document.getElementById('modalOverlay').classList.add('active');
}
function closeModal() { document.getElementById('modalOverlay').classList.remove('active'); }
// ========== 购物车 ==========
function addToCart(id) {
var p = allProducts.find(function(x){ return x.id === id; });
if (!p) return;
var existing = cart.find(function(c){ return c.id === id; });
if (existing) { existing.qty++; } else { cart.push({ id: id, name: p.name, price: p.price, icon: p.icon, qty: 1 }); }
updateCartUI();
showToast('已加入购物车: ' + p.name);
}
function updateCartUI() {
var badge = document.getElementById('cartBadge');
var totalQty = cart.reduce(function(s, c){ return s + c.qty; }, 0);
badge.textContent = totalQty;
badge.style.display = totalQty > 0 ? 'flex' : 'none';
var items = document.getElementById('cartItems');
if (!cart.length) {
items.innerHTML = '<div class="cart-empty">购物车是空的<br>快去挑选心仪的商品吧</div>';
} else {
items.innerHTML = cart.map(function(c) {
return '<div class="cart-item">' +
'<div class="cart-item-img">' + (c.icon || '🔌') + '</div>' +
'<div class="cart-item-info">' +
'<div class="cart-item-name">' + c.name + '</div>' +
'<div class="cart-item-price">' + fmtPrice(c.price) + '</div>' +
'<div class="cart-item-qty">' +
'<button class="qty-btn" onclick="changeQty(' + c.id + ',-1)">−</button>' +
'<span>' + c.qty + '</span>' +
'<button class="qty-btn" onclick="changeQty(' + c.id + ',1)">+</button>' +
'</div>' +
'</div>' +
'</div>';
}).join('');
}
var total = cart.reduce(function(s, c){ return s + c.price * c.qty; }, 0);
document.getElementById('cartTotal').textContent = fmtPrice(total);
document.getElementById('checkoutBtn').disabled = cart.length === 0;
}
function changeQty(id, delta) {
var item = cart.find(function(c){ return c.id === id; });
if (!item) return;
item.qty += delta;
if (item.qty <= 0) cart = cart.filter(function(c){ return c.id !== id; });
updateCartUI();
}
function toggleCart() {
document.getElementById('cartOverlay').classList.toggle('active');
document.getElementById('cartDrawer').classList.toggle('active');
}
// ========== AAA级古树 Canvas 壁画 + 光追生命力 ==========
(function() {
var canvas = document.getElementById('treeCanvas');
var ctx = canvas.getContext('2d');
var W = 0, H = 0, dpr = window.devicePixelRatio || 1;
var mx = 0, my = 0, hasMouse = false;
var branches = [];
var leafClusters = [];
var fireflies = [];
var energyPulses = []; // 沿树干流动的能量脉冲
var spores = []; // 大气孢子粒子
var godRays = []; // 体积光
function resize() {
var rect = canvas.getBoundingClientRect();
W = rect.width; H = rect.height;
canvas.width = W * dpr; canvas.height = H * dpr;
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
mx = W / 2; my = H / 2;
buildTree();
initAtmosphere();
}
// ========== 构建枝繁叶茂的大树 ==========
function buildTree() {
branches = [];
leafClusters = [];
fireflies = [];
energyPulses = [];
var trunkX = W * 0.5;
var trunkY = H * 0.92;
var trunkH = H * 0.32;
function branch(x, y, angle, length, depth, width, parentIdx) {
if (depth <= 0 || length < 6) {
// 枝末生成大量叶子簇
var clusterSize = 4 + Math.floor(Math.random() * 4);
for (var i = 0; i < clusterSize; i++) {
var lx = x + (Math.random() - 0.5) * 40;
var ly = y + (Math.random() - 0.5) * 35;
var leaves = 3 + Math.floor(Math.random() * 4);
for (var j = 0; j < leaves; j++) {
leafClusters.push({
x: lx + (Math.random() - 0.5) * 18,
y: ly + (Math.random() - 0.5) * 18,
size: 2 + Math.random() * 5,
hue: 95 + Math.random() * 55,
sat: 45 + Math.random() * 25,
lit: 35 + Math.random() * 20,
alpha: 0.35 + Math.random() * 0.3,
sway: Math.random() * Math.PI * 2,
swaySpeed: 0.5 + Math.random() * 0.5
});
}
}
return;
}
var ex = x + Math.cos(angle) * length;
var ey = y + Math.sin(angle) * length;
var branchIdx = branches.length;
branches.push({
x1: x, y1: y, x2: ex, y2: ey,
width: width, depth: depth,
parentIdx: parentIdx,
sway: Math.random() * Math.PI * 2,
swayAmount: (8 - depth) * 0.5,
baseAngle: angle
});
// 沿枝干放置萤火虫
var fireflyCount = depth > 4 ? 2 : 1;
for (var f = 0; f < fireflyCount; f++) {
fireflies.push({
x: x, y: y, baseX: x, baseY: y,
tx: ex, ty: ey,
branchIdx: branchIdx,
progress: Math.random(),
speed: 0.0015 + Math.random() * 0.003,
size: 1 + Math.random() * 2,
hue: 110 + Math.random() * 50,
offset: Math.random() * Math.PI * 2
});
}
// 能量脉冲沿枝干流动
if (depth >= 3 && Math.random() < 0.4) {
energyPulses.push({
branchIdx: branchIdx,
progress: Math.random(),
speed: 0.005 + Math.random() * 0.008,
size: 2 + Math.random() * 2,
life: 1
});
}
// 分叉
var nChildren = depth > 5 ? 2 : (Math.random() < 0.35 ? 3 : 2);
for (var i = 0; i < nChildren; i++) {
var spread = 0.3 + Math.random() * 0.25;
var newAngle = angle + (i / (nChildren - 1) - 0.5) * spread * 2 + (Math.random() - 0.5) * 0.12;
var newLen = length * (0.68 + Math.random() * 0.12);
branch(ex, ey, newAngle, newLen, depth - 1, width * 0.72, branchIdx);
}
}
// 主干 — 更深递归获得更多枝叶
branch(trunkX, trunkY, -Math.PI / 2, trunkH, 8, 16, -1);
// 树根系统
for (var r = 0; r < 6; r++) {
var rAngle = -Math.PI / 2 + (r - 2.5) * 0.25;
var rLen = trunkH * 0.3;
branches.push({
x1: trunkX, y1: trunkY,
x2: trunkX + Math.cos(rAngle) * rLen,
y2: trunkY + Math.sin(rAngle) * rLen * 0.2,
width: 7, depth: 0, isRoot: true,
sway: 0, swayAmount: 0, baseAngle: rAngle
});
}
}
// ========== 大气粒子 ==========
function initAtmosphere() {
spores = [];
for (var i = 0; i < 40; i++) {
spores.push({
x: Math.random() * W,
y: Math.random() * H,
vx: (Math.random() - 0.5) * 0.3,
vy: -0.1 - Math.random() * 0.3,
size: 0.5 + Math.random() * 1.5,
alpha: 0.1 + Math.random() * 0.3,
hue: 90 + Math.random() * 40
});
}
godRays = [];
for (var i = 0; i < 5; i++) {
godRays.push({
x: W * (0.2 + i * 0.15),
angle: -Math.PI / 2 + (Math.random() - 0.5) * 0.3,
width: 80 + Math.random() * 60,
opacity: 0.04 + Math.random() * 0.04
});
}
}
// ========== 鼠标交互 ==========
canvas.parentElement.addEventListener('mousemove', function(e) {
var rect = canvas.getBoundingClientRect();
mx = e.clientX - rect.left;
my = e.clientY - rect.top;
hasMouse = true;
});
canvas.parentElement.addEventListener('mouseleave', function() { hasMouse = false; });
// ========== 主渲染循环 ==========
function drawTree() {
var isDark = document.body.getAttribute('data-theme') === 'dark';
var time = Date.now() * 0.001;
// === 1. 背景天空渐变 ===
var skyGrad = ctx.createLinearGradient(0, 0, 0, H);
if (isDark) {
skyGrad.addColorStop(0, '#040806');
skyGrad.addColorStop(0.3, '#080f0a');
skyGrad.addColorStop(0.6, '#0a120a');
skyGrad.addColorStop(1, '#060a06');
} else {
skyGrad.addColorStop(0, '#e8e4d8');
skyGrad.addColorStop(0.3, '#f0ede2');
skyGrad.addColorStop(0.6, '#f5f3ec');
skyGrad.addColorStop(1, '#efece2');
}
ctx.fillStyle = skyGrad;
ctx.fillRect(0, 0, W, H);
// === 2. 体积光(God Rays)===
if (isDark) {
godRays.forEach(function(gr) {
var len = H * 0.9;
var ex = gr.x + Math.cos(gr.angle) * len;
var ey = Math.sin(gr.angle) * len;
var rg = ctx.createLinearGradient(gr.x, 0, ex, ey);
rg.addColorStop(0, 'rgba(180,220,140,' + gr.opacity + ')');
rg.addColorStop(0.5, 'rgba(150,200,120,' + (gr.opacity * 0.5) + ')');
rg.addColorStop(1, 'transparent');
ctx.fillStyle = rg;
ctx.beginPath();
ctx.moveTo(gr.x - gr.width / 2, 0);
ctx.lineTo(gr.x + gr.width / 2, 0);
ctx.lineTo(ex + gr.width, ey);
ctx.lineTo(ex - gr.width, ey);
ctx.closePath();
ctx.fill();
});
}
// === 3. 地面雾气 ===
var fogGrad = ctx.createLinearGradient(0, H * 0.6, 0, H);
if (isDark) {
fogGrad.addColorStop(0, 'transparent');
fogGrad.addColorStop(1, 'rgba(20,35,18,0.5)');
} else {
fogGrad.addColorStop(0, 'transparent');
fogGrad.addColorStop(1, 'rgba(180,175,155,0.3)');
}
ctx.fillStyle = fogGrad;
ctx.fillRect(0, H * 0.6, W, H * 0.4);
// === 4. 绘制树枝(带摇摆和深度感)===
branches.forEach(function(b) {
var swayX = 0, swayY = 0;
if (!b.isRoot && b.swayAmount > 0) {
swayX = Math.sin(time * 0.8 + b.sway) * b.swayAmount;
swayY = Math.cos(time * 0.6 + b.sway) * b.swayAmount * 0.3;
}
b._sx2 = b.x2 + swayX;
b._sy2 = b.y2 + swayY;
// 鼠标光照增强
var midX = (b.x1 + b._sx2) / 2;
var midY = (b.y1 + b._sy2) / 2;
var dx = mx - midX, dy = my - midY;
var dist = Math.sqrt(dx * dx + dy * dy);
var lightBoost = hasMouse && dist < 180 ? (1 - dist / 180) : 0;
ctx.beginPath();
ctx.moveTo(b.x1, b.y1);
ctx.lineTo(b._sx2, b._sy2);
var baseColor, r, g, bl;
if (b.isRoot) {
r = isDark ? 60 + lightBoost * 40 : 90;
g = isDark ? 45 + lightBoost * 30 : 70;
bl = isDark ? 30 + lightBoost * 20 : 45;
} else {
var depthFactor = b.depth / 8;
r = (isDark ? 80 : 110) + lightBoost * 50 + depthFactor * 20;
g = (isDark ? 65 : 90) + lightBoost * 35 + depthFactor * 15;
bl = (isDark ? 45 : 60) + lightBoost * 20;
}
ctx.strokeStyle = 'rgba(' + Math.round(r) + ',' + Math.round(g) + ',' + Math.round(bl) + ',' + (0.65 + lightBoost * 0.25) + ')';
ctx.lineWidth = b.width;
ctx.lineCap = 'round';
ctx.stroke();
// 树干高光
if (b.depth >= 6 && !b.isRoot) {
ctx.beginPath();
ctx.moveTo(b.x1 - b.width * 0.2, b.y1);
ctx.lineTo(b._sx2 - b.width * 0.2, b._sy2);
ctx.strokeStyle = 'rgba(' + Math.round(r + 30) + ',' + Math.round(g + 25) + ',' + Math.round(bl + 15) + ',0.3)';
ctx.lineWidth = b.width * 0.3;
ctx.stroke();
}
});
// === 5. 绘制叶簇(枝繁叶茂)===
leafClusters.forEach(function(l) {
var sway = Math.sin(time * l.swaySpeed + l.sway) * 3;
var x = l.x + sway;
var y = l.y + Math.cos(time * 0.7 + l.sway) * 2;
// 鼠标附近叶子发光
var dx = mx - x, dy = my - y;
var dist = Math.sqrt(dx * dx + dy * dy);
var glow = hasMouse && dist < 160 ? (1 - dist / 160) : 0;
var lit = l.lit + glow * 25;
var alpha = l.alpha + glow * 0.4;
ctx.beginPath();
ctx.arc(x, y, l.size, 0, Math.PI * 2);
ctx.fillStyle = 'hsla(' + l.hue + ',' + l.sat + '%,' + lit + '%,' + alpha + ')';
ctx.fill();
// 发光叶片
if (glow > 0.2) {
ctx.beginPath();
ctx.arc(x, y, l.size * 2.5, 0, Math.PI * 2);
var lg = ctx.createRadialGradient(x, y, 0, x, y, l.size * 2.5);
lg.addColorStop(0, 'hsla(' + l.hue + ',70%,55%,' + (glow * 0.35) + ')');
lg.addColorStop(1, 'transparent');
ctx.fillStyle = lg;
ctx.fill();
}
});
// === 6. 能量脉冲沿树干流动(生命力)===
energyPulses.forEach(function(ep) {
var b = branches[ep.branchIdx];
if (!b || !b._sx2) return;
ep.progress += ep.speed;
if (ep.progress > 1) { ep.progress = 0; ep.life = 1; }
var px = b.x1 + (b._sx2 - b.x1) * ep.progress;
var py = b.y1 + (b._sy2 - b.y1) * ep.progress;
// 鼠标附近的脉冲更亮
var dx = mx - px, dy = my - py;
var dist = Math.sqrt(dx * dx + dy * dy);
var boost = hasMouse && dist < 250 ? (1 - dist / 250) : 0;
var brightness = 0.5 + boost * 0.5;
ctx.beginPath();
ctx.arc(px, py, ep.size * (1 + boost), 0, Math.PI * 2);
ctx.fillStyle = 'rgba(150,255,120,' + brightness + ')';
ctx.fill();
ctx.beginPath();
ctx.arc(px, py, ep.size * 4, 0, Math.PI * 2);
var pg = ctx.createRadialGradient(px, py, 0, px, py, ep.size * 4);
pg.addColorStop(0, 'rgba(120,255,100,' + (brightness * 0.4) + ')');
pg.addColorStop(1, 'transparent');
ctx.fillStyle = pg;
ctx.fill();
});
// === 7. 萤火虫粒子(生命力流动)===
fireflies.forEach(function(f) {
f.progress += f.speed;
if (f.progress > 1) f.progress = 0;
var b = branches[f.branchIdx];
if (!b || !b._sx2) return;
var px = b.x1 + (b._sx2 - b.x1) * f.progress;
var py = b.y1 + (b._sy2 - b.y1) * f.progress;
px += Math.sin(time * 2 + f.offset) * 3;
py += Math.cos(time * 1.5 + f.offset) * 2;
// 鼠标光追激活
var dx = mx - px, dy = my - py;
var dist = Math.sqrt(dx * dx + dy * dy);
var activate = hasMouse && dist < 220 ? (1 - dist / 220) : 0;
var brightness = 0.35 + activate * 0.65;
var size = f.size * (1 + activate * 1.8);
var hue = activate > 0.3 ? 50 + activate * 30 : f.hue;
// 萤火虫核心
ctx.beginPath();
ctx.arc(px, py, size, 0, Math.PI * 2);
ctx.fillStyle = 'hsla(' + hue + ',95%,' + (55 + activate * 20) + '%,' + brightness + ')';
ctx.fill();
// 光晕
ctx.beginPath();
ctx.arc(px, py, size * 5, 0, Math.PI * 2);
var gl = ctx.createRadialGradient(px, py, 0, px, py, size * 5);
gl.addColorStop(0, 'hsla(' + hue + ',90%,60%,' + (brightness * 0.35) + ')');
gl.addColorStop(1, 'transparent');
ctx.fillStyle = gl;
ctx.fill();
// 鼠标光追连线 — 生命力从鼠标流向树
if (activate > 0.15) {
ctx.beginPath();
ctx.moveTo(px, py);
ctx.lineTo(mx, my);
var lg = ctx.createLinearGradient(px, py, mx, my);
lg.addColorStop(0, 'hsla(' + hue + ',80%,60%,' + (activate * 0.3) + ')');
lg.addColorStop(1, 'hsla(' + hue + ',80%,70%,' + (activate * 0.05) + ')');
ctx.strokeStyle = lg;
ctx.lineWidth = 1;
ctx.stroke();
}
});
// === 8. 大气孢子粒子 ===
spores.forEach(function(s) {
s.x += s.vx;
s.y += s.vy;
if (s.y < -10) { s.y = H + 10; s.x = Math.random() * W; }
if (s.x < -10) s.x = W + 10;
if (s.x > W + 10) s.x = -10;
var dx = mx - s.x, dy = my - s.y;
var dist = Math.sqrt(dx * dx + dy * dy);
var boost = hasMouse && dist < 150 ? (1 - dist / 150) : 0;
ctx.beginPath();
ctx.arc(s.x, s.y, s.size * (1 + boost), 0, Math.PI * 2);
ctx.fillStyle = 'hsla(' + s.hue + ',60%,70%,' + (s.alpha + boost * 0.3) + ')';
ctx.fill();
});
// === 9. 鼠标光源 — 生命力的源头 ===
if (hasMouse) {
// 外层大光晕
var outerGlow = ctx.createRadialGradient(mx, my, 0, mx, my, 180);
outerGlow.addColorStop(0, 'rgba(140,255,110,0.12)');
outerGlow.addColorStop(0.4, 'rgba(120,220,90,0.05)');
outerGlow.addColorStop(1, 'transparent');
ctx.fillStyle = outerGlow;
ctx.beginPath();
ctx.arc(mx, my, 180, 0, Math.PI * 2);
ctx.fill();
// 中层光晕
ctx.beginPath();
ctx.arc(mx, my, 60, 0, Math.PI * 2);
var midGlow = ctx.createRadialGradient(mx, my, 0, mx, my, 60);
midGlow.addColorStop(0, 'rgba(160,255,120,0.25)');
midGlow.addColorStop(1, 'transparent');
ctx.fillStyle = midGlow;
ctx.fill();
// 旋转放射光线
for (var k = 0; k < 8; k++) {
var angle = (k / 8) * Math.PI * 2 + time * 0.25;
var len = 80 + Math.sin(time * 2 + k) * 20;
var ex = mx + Math.cos(angle) * len;
var ey = my + Math.sin(angle) * len;
var rg = ctx.createLinearGradient(mx, my, ex, ey);
rg.addColorStop(0, 'rgba(140,255,100,0.15)');
rg.addColorStop(1, 'transparent');
ctx.beginPath();
ctx.moveTo(mx, my);
ctx.lineTo(ex, ey);
ctx.strokeStyle = rg;
ctx.lineWidth = 2;
ctx.stroke();
}
// 核心光点
ctx.beginPath();
ctx.arc(mx, my, 4, 0, Math.PI * 2);
ctx.fillStyle = 'rgba(200,255,170,0.95)';
ctx.fill();
ctx.beginPath();
ctx.arc(mx, my, 8, 0, Math.PI * 2);
ctx.fillStyle = 'rgba(160,255,130,0.4)';
ctx.fill();
}
requestAnimationFrame(drawTree);
}
resize();
window.addEventListener('resize', resize);
drawTree();
})();
// ========== 商品区域背景 — 模糊古树 ==========
(function() {
var bg = document.getElementById('productsBg');
var canvas = document.createElement('canvas');
bg.appendChild(canvas);
var ctx = canvas.getContext('2d');
var W = 0, H = 0;
function resize() {
W = bg.offsetWidth; H = bg.offsetHeight;
canvas.width = W; canvas.height = H;
draw();
}
function draw() {
var isDark = document.body.getAttribute('data-theme') === 'dark';
ctx.clearRect(0, 0, W, H);
var trunkX = W * 0.5, trunkY = H * 0.98;
var trunkH = H * 0.45;
// 背景渐变
var bgGrad = ctx.createRadialGradient(W * 0.5, H * 0.6, 0, W * 0.5, H * 0.6, W * 0.7);
if (isDark) {
bgGrad.addColorStop(0, 'rgba(15,25,15,0.15)');
bgGrad.addColorStop(1, 'rgba(8,12,8,0.1)');
} else {
bgGrad.addColorStop(0, 'rgba(200,195,175,0.12)');
bgGrad.addColorStop(1, 'rgba(180,175,155,0.08)');
}
ctx.fillStyle = bgGrad;
ctx.fillRect(0, 0, W, H);
function branch(x, y, angle, length, depth, width) {
if (depth <= 0 || length < 5) {
// 叶簇
for (var i = 0; i < 5; i++) {
ctx.beginPath();
ctx.arc(x + (Math.random() - 0.5) * 30, y + (Math.random() - 0.5) * 25, 3 + Math.random() * 4, 0, Math.PI * 2);
ctx.fillStyle = isDark ? 'rgba(80,130,60,0.12)' : 'rgba(100,140,70,0.08)';
ctx.fill();
}
return;
}
var ex = x + Math.cos(angle) * length;
var ey = y + Math.sin(angle) * length;
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(ex, ey);
ctx.strokeStyle = isDark ? 'rgba(90,70,50,0.2)' : 'rgba(100,85,60,0.12)';
ctx.lineWidth = width;
ctx.lineCap = 'round';
ctx.stroke();
var n = 2;
for (var i = 0; i < n; i++) {
var a2 = angle + (i - 0.5) * 0.4 + (Math.random() - 0.5) * 0.1;
branch(ex, ey, a2, length * 0.7, depth - 1, width * 0.7);
}
}
branch(trunkX, trunkY, -Math.PI / 2, trunkH, 7, 14);
// 模糊层
if (canvas.width > 0 && canvas.height > 0) {
ctx.filter = 'blur(4px)';
ctx.globalAlpha = 0.6;
ctx.drawImage(canvas, 0, 0);
ctx.filter = 'none';
ctx.globalAlpha = 1;
}
}
resize();
window.addEventListener('resize', resize);
document.body.addEventListener('click', function() { setTimeout(resize, 100); }, true);
})();
// ========== 初始化 ==========
loadProducts();
updateCartUI();
</script>
</body>
</html>