pin_drop当前位置:知识文库 ❯ 图文
实战项目:项目04:电商产品展示页 - 详细教程与实战指南
一、项目简介
电商产品展示页是线上购物的核心页面,直接影响用户的购买决策。一个优秀的产品展示页需要在有限的空间内充分展示产品信息、激发购买欲望,同时提供流畅的交互体验,让用户轻松完成从了解到下单的全过程。
本项目将构建一个功能丰富的电商产品展示页,包含产品图片轮播、产品信息展示、规格选择、购物车、用户评价和相关推荐等核心模块。项目实现了图片放大镜、数量选择器、评分组件等交互功能,为用户提供沉浸式的购物体验。
二、需求分析
功能需求
产品图片轮播:多张产品图片切换,支持缩略图导航和自动播放
图片放大镜:鼠标悬停在主图上时显示放大细节
产品信息:名称、价格、折扣、描述、评分等核心信息
规格选择:颜色、尺寸等规格的选择,选中状态和库存提示
数量选择器:增减按钮和直接输入,限制库存范围
购物车:添加到购物车,购物车图标显示数量,弹出购物车预览
用户评价:评分分布、评价列表、筛选排序
相关推荐:相似产品卡片展示
交互需求
图片轮播支持左右箭头和缩略图切换
鼠标悬停主图时显示放大镜效果
规格选择后更新价格和库存状态
数量选择器有边界限制和输入验证
添加购物车时有动画反馈
评价支持按星级筛选
用户场景
用户在产品列表中点击进入产品详情页
用户通过图片轮播和放大镜仔细查看产品细节
用户选择规格和数量后加入购物车
用户查看其他买家的评价辅助决策
用户浏览相关推荐发现更多产品
三、技术选型
四、页面结构设计
代码示例
<body>
├── <header> 顶部导航
│ ├── Logo
│ ├── 搜索栏
│ └── 购物车图标(含数量)
├── 面包屑导航
├── <main> 产品展示区
│ ├── 产品图片区
│ │ ├── 主图 + 放大镜
│ │ └── 缩略图列表
│ └── 产品信息区
│ ├── 名称、评分、价格
│ ├── 规格选择
│ ├── 数量选择器
│ ├── 购买按钮
│ └── 服务保障
├── <section> 商品详情Tab
├── <section> 用户评价
│ ├── 评分分布
│ └── 评价列表
├── <section> 相关推荐
└── 购物车弹出层五、完整代码实现
以下是电商产品展示页的完整HTML代码实现,包含CSS样式和JavaScript交互逻辑:
代码示例
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>无线降噪耳机 Pro - 星辰商城</title>
<style>
:root {
--color-primary: #e11d48;
--color-primary-light: #f43f5e;
--color-primary-dark: #be123c;
--color-price: #e11d48;
--color-bg: #f5f5f5;
--color-bg-white: #ffffff;
--color-text: #1a1a1a;
--color-text-secondary: #666666;
--color-text-light: #999999;
--color-border: #e5e5e5;
--color-shadow: rgba(0, 0, 0, 0.06);
--color-star: #f59e0b;
--color-tag-bg: #fff1f2;
--color-tag-text: #e11d48;
--radius: 8px;
--transition: 0.3s ease;
}
*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Noto Sans SC", sans-serif;
background: var(--color-bg);
color: var(--color-text);
line-height: 1.6;
}
a { text-decoration: none; color: inherit; }
ul { list-style: none; }
button { cursor: pointer; border: none; font-family: inherit; }
/* ========== 顶部导航 ========== */
.top-nav {
background: var(--color-bg-white);
border-bottom: 1px solid var(--color-border);
position: sticky;
top: 0;
z-index: 100;
}
.nav-inner {
max-width: 1200px;
margin: 0 auto;
padding: 0 24px;
height: 60px;
display: flex;
align-items: center;
justify-content: space-between;
}
.nav-logo {
font-size: 1.3rem;
font-weight: 800;
color: var(--color-primary);
}
.nav-search {
flex: 1;
max-width: 400px;
margin: 0 32px;
position: relative;
}
.nav-search input {
width: 100%;
padding: 8px 16px 8px 36px;
border: 2px solid var(--color-border);
border-radius: 20px;
font-size: 0.88rem;
background: var(--color-bg);
transition: all var(--transition);
}
.nav-search input:focus {
outline: none;
border-color: var(--color-primary);
}
.nav-search .search-icon {
position: absolute;
left: 12px;
top: 50%;
transform: translateY(-50%);
color: var(--color-text-light);
}
.nav-cart {
position: relative;
background: none;
font-size: 1.4rem;
padding: 8px;
color: var(--color-text);
transition: color var(--transition);
}
.nav-cart:hover { color: var(--color-primary); }
.cart-badge {
position: absolute;
top: 0;
right: -2px;
min-width: 18px;
height: 18px;
background: var(--color-primary);
color: white;
border-radius: 9px;
font-size: 0.7rem;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
padding: 0 4px;
transform: scale(0);
transition: transform 0.3s cubic-bezier(0.68, -0.55, 0.27, 1.55);
}
.cart-badge.show { transform: scale(1); }
/* ========== 面包屑 ========== */
.breadcrumb {
max-width: 1200px;
margin: 0 auto;
padding: 16px 24px;
font-size: 0.85rem;
color: var(--color-text-light);
}
.breadcrumb a { color: var(--color-text-secondary); }
.breadcrumb a:hover { color: var(--color-primary); }
.breadcrumb span { margin: 0 6px; }
/* ========== 产品展示区 ========== */
.product-main {
max-width: 1200px;
margin: 0 auto;
padding: 0 24px 40px;
display: grid;
grid-template-columns: 1fr 1fr;
gap: 40px;
background: var(--color-bg-white);
border-radius: var(--radius);
padding: 32px;
}
/* 图片区域 */
.product-gallery {
position: relative;
}
.main-image-wrapper {
position: relative;
width: 100%;
aspect-ratio: 1;
border-radius: var(--radius);
overflow: hidden;
background: #f9f9f9;
cursor: crosshair;
margin-bottom: 12px;
}
.main-image {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: 8rem;
background: linear-gradient(135deg, #fce7f3, #fbcfe8);
transition: transform 0.1s ease;
user-select: none;
}
.zoom-lens {
position: absolute;
width: 150px;
height: 150px;
border: 2px solid var(--color-primary);
border-radius: 4px;
background: rgba(255, 255, 255, 0.3);
pointer-events: none;
display: none;
z-index: 2;
}
.zoom-result {
position: absolute;
top: 0;
right: -320px;
width: 300px;
height: 300px;
border: 1px solid var(--color-border);
border-radius: var(--radius);
overflow: hidden;
display: none;
z-index: 10;
background: #f9f9f9;
}
.zoom-result-inner {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: 20rem;
background: linear-gradient(135deg, #fce7f3, #fbcfe8);
}
.gallery-nav {
position: absolute;
top: 50%;
transform: translateY(-50%);
width: 36px;
height: 36px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.9);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
color: var(--color-text);
z-index: 3;
transition: all var(--transition);
}
.gallery-nav:hover { background: white; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); }
.gallery-prev { left: 12px; }
.gallery-next { right: 12px; }
.thumbnail-list {
display: flex;
gap: 8px;
}
.thumbnail {
width: 64px;
height: 64px;
border-radius: 6px;
border: 2px solid transparent;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.8rem;
background: #f9f9f9;
transition: all var(--transition);
overflow: hidden;
}
.thumbnail:hover { border-color: var(--color-primary-light); }
.thumbnail.active { border-color: var(--color-primary); }
/* 产品信息区 */
.product-info {
padding-left: 20px;
}
.product-title {
font-size: 1.6rem;
font-weight: 700;
line-height: 1.4;
margin-bottom: 12px;
}
.product-subtitle {
font-size: 0.92rem;
color: var(--color-text-secondary);
margin-bottom: 16px;
}
.product-rating {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 20px;
font-size: 0.88rem;
}
.stars {
display: flex;
gap: 2px;
color: var(--color-star);
font-size: 1rem;
}
.stars .star-empty { color: #ddd; }
.rating-score {
font-weight: 700;
color: var(--color-star);
}
.review-count {
color: var(--color-text-light);
}
.price-box {
background: linear-gradient(135deg, #fff1f2, #ffe4e6);
padding: 20px;
border-radius: var(--radius);
margin-bottom: 24px;
}
.price-current {
font-size: 2rem;
font-weight: 800;
color: var(--color-price);
}
.price-current .yen { font-size: 1.2rem; }
.price-original {
font-size: 0.95rem;
color: var(--color-text-light);
text-decoration: line-through;
margin-left: 12px;
}
.price-discount {
display: inline-block;
padding: 2px 8px;
background: var(--color-primary);
color: white;
border-radius: 4px;
font-size: 0.75rem;
font-weight: 600;
margin-left: 8px;
vertical-align: middle;
}
/* 规格选择 */
.spec-section {
margin-bottom: 20px;
}
.spec-label {
font-size: 0.88rem;
font-weight: 600;
margin-bottom: 10px;
color: var(--color-text);
}
.spec-label .selected-val {
color: var(--color-text-secondary);
font-weight: 400;
margin-left: 8px;
}
.spec-options {
display: flex;
flex-wrap: wrap;
gap: 10px;
}
.spec-option {
padding: 8px 20px;
border: 2px solid var(--color-border);
border-radius: 6px;
font-size: 0.88rem;
cursor: pointer;
transition: all var(--transition);
background: var(--color-bg-white);
position: relative;
}
.spec-option:hover { border-color: var(--color-primary-light); }
.spec-option.selected {
border-color: var(--color-primary);
color: var(--color-primary);
background: var(--color-tag-bg);
}
.spec-option.selected::after {
content: "";
position: absolute;
right: 0;
bottom: 0;
width: 0;
height: 0;
border-style: solid;
border-width: 0 0 24px 24px;
border-color: transparent transparent var(--color-primary) transparent;
}
.spec-option.out-of-stock {
opacity: 0.4;
cursor: not-allowed;
text-decoration: line-through;
}
/* 数量选择器 */
.quantity-section {
margin-bottom: 24px;
}
.quantity-control {
display: inline-flex;
align-items: center;
border: 2px solid var(--color-border);
border-radius: 6px;
overflow: hidden;
}
.qty-btn {
width: 36px;
height: 36px;
background: var(--color-bg);
border: none;
font-size: 1.1rem;
color: var(--color-text);
display: flex;
align-items: center;
justify-content: center;
transition: all var(--transition);
}
.qty-btn:hover { background: var(--color-border); }
.qty-btn:disabled { opacity: 0.3; cursor: not-allowed; }
.qty-input {
width: 50px;
height: 36px;
border: none;
border-left: 1px solid var(--color-border);
border-right: 1px solid var(--color-border);
text-align: center;
font-size: 0.92rem;
font-weight: 600;
font-family: inherit;
background: var(--color-bg-white);
}
.qty-input:focus { outline: none; }
.stock-info {
display: inline-block;
margin-left: 12px;
font-size: 0.82rem;
color: var(--color-text-light);
}
/* 购买按钮 */
.action-buttons {
display: flex;
gap: 12px;
margin-bottom: 24px;
}
.btn-buy {
flex: 1;
padding: 14px;
background: var(--color-primary);
color: white;
border-radius: var(--radius);
font-size: 1rem;
font-weight: 600;
transition: all var(--transition);
}
.btn-buy:hover { background: var(--color-primary-dark); transform: translateY(-1px); }
.btn-cart {
flex: 1;
padding: 14px;
background: var(--color-tag-bg);
color: var(--color-primary);
border: 2px solid var(--color-primary);
border-radius: var(--radius);
font-size: 1rem;
font-weight: 600;
transition: all var(--transition);
}
.btn-cart:hover { background: var(--color-primary); color: white; transform: translateY(-1px); }
.btn-cart.added {
background: #22c55e;
border-color: #22c55e;
color: white;
}
/* 服务保障 */
.service-guarantees {
display: flex;
flex-wrap: wrap;
gap: 16px;
padding: 16px 0;
border-top: 1px solid var(--color-border);
font-size: 0.82rem;
color: var(--color-text-secondary);
}
.service-item {
display: flex;
align-items: center;
gap: 4px;
}
.service-item .check { color: #22c55e; font-weight: 700; }
/* ========== 评价区域 ========== */
.reviews-section {
max-width: 1200px;
margin: 0 auto 40px;
padding: 0 24px;
}
.reviews-card {
background: var(--color-bg-white);
border-radius: var(--radius);
padding: 32px;
}
.reviews-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 24px;
}
.reviews-header h2 {
font-size: 1.3rem;
font-weight: 700;
}
.review-filters {
display: flex;
gap: 8px;
}
.review-filter-btn {
padding: 6px 14px;
border-radius: 20px;
font-size: 0.82rem;
background: var(--color-bg);
border: 1px solid var(--color-border);
color: var(--color-text-secondary);
transition: all var(--transition);
}
.review-filter-btn:hover,
.review-filter-btn.active {
background: var(--color-tag-bg);
border-color: var(--color-primary);
color: var(--color-primary);
}
.rating-summary {
display: flex;
gap: 32px;
margin-bottom: 28px;
padding-bottom: 24px;
border-bottom: 1px solid var(--color-border);
}
.rating-overall {
text-align: center;
min-width: 100px;
}
.rating-overall .big-score {
font-size: 3rem;
font-weight: 800;
color: var(--color-star);
line-height: 1;
}
.rating-overall .score-label {
font-size: 0.82rem;
color: var(--color-text-light);
margin-top: 4px;
}
.rating-bars {
flex: 1;
}
.rating-bar-row {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 6px;
font-size: 0.82rem;
}
.rating-bar-row .bar-label { width: 30px; color: var(--color-text-secondary); }
.rating-bar-row .bar-track { flex: 1; height: 8px; background: #f0f0f0; border-radius: 4px; overflow: hidden; }
.rating-bar-row .bar-fill { height: 100%; background: var(--color-star); border-radius: 4px; transition: width 0.5s ease; }
.rating-bar-row .bar-count { width: 30px; text-align: right; color: var(--color-text-light); }
.review-list {
display: flex;
flex-direction: column;
gap: 20px;
}
.review-item {
padding-bottom: 20px;
border-bottom: 1px solid var(--color-border);
}
.review-item:last-child { border-bottom: none; }
.review-item-header {
display: flex;
align-items: center;
gap: 12px;
margin-bottom: 8px;
}
.reviewer-avatar {
width: 36px;
height: 36px;
border-radius: 50%;
background: linear-gradient(135deg, #ddd, #bbb);
display: flex;
align-items: center;
justify-content: center;
font-size: 14px;
color: white;
font-weight: 700;
}
.reviewer-name { font-weight: 600; font-size: 0.9rem; }
.review-date { font-size: 0.78rem; color: var(--color-text-light); margin-left: auto; }
.review-stars { font-size: 0.85rem; color: var(--color-star); margin-bottom: 6px; }
.review-text { font-size: 0.9rem; color: var(--color-text-secondary); line-height: 1.7; }
.review-specs {
margin-top: 8px;
font-size: 0.78rem;
color: var(--color-text-light);
}
/* ========== 相关推荐 ========== */
.recommend-section {
max-width: 1200px;
margin: 0 auto 40px;
padding: 0 24px;
}
.recommend-section h2 {
font-size: 1.3rem;
font-weight: 700;
margin-bottom: 20px;
}
.recommend-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
gap: 16px;
}
.recommend-card {
background: var(--color-bg-white);
border-radius: var(--radius);
overflow: hidden;
transition: all var(--transition);
cursor: pointer;
}
.recommend-card:hover {
transform: translateY(-4px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
}
.recommend-card .card-img {
width: 100%;
aspect-ratio: 1;
background: linear-gradient(135deg, #f0f0f0, #e0e0e0);
display: flex;
align-items: center;
justify-content: center;
font-size: 3rem;
}
.recommend-card .card-info {
padding: 12px;
}
.recommend-card .card-name {
font-size: 0.88rem;
font-weight: 600;
margin-bottom: 6px;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.recommend-card .card-price {
font-size: 1rem;
font-weight: 700;
color: var(--color-price);
}
/* ========== 购物车弹出层 ========== */
.cart-popup {
position: fixed;
top: 60px;
right: 24px;
width: 340px;
background: var(--color-bg-white);
border-radius: var(--radius);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
z-index: 200;
padding: 20px;
display: none;
animation: slideDown 0.3s ease;
}
.cart-popup.show { display: block; }
@keyframes slideDown {
from { opacity: 0; transform: translateY(-10px); }
to { opacity: 1; transform: translateY(0); }
}
.cart-popup h3 {
font-size: 1rem;
font-weight: 700;
margin-bottom: 16px;
display: flex;
justify-content: space-between;
align-items: center;
}
.cart-popup .close-popup {
background: none;
font-size: 1.2rem;
color: var(--color-text-light);
}
.cart-item {
display: flex;
gap: 12px;
padding: 12px 0;
border-bottom: 1px solid var(--color-border);
}
.cart-item-img {
width: 60px;
height: 60px;
border-radius: 6px;
background: #f9f9f9;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.8rem;
flex-shrink: 0;
}
.cart-item-info h4 { font-size: 0.85rem; font-weight: 600; margin-bottom: 2px; }
.cart-item-info .cart-spec { font-size: 0.75rem; color: var(--color-text-light); }
.cart-item-info .cart-price-row { display: flex; justify-content: space-between; align-items: center; margin-top: 6px; }
.cart-item-info .cart-item-price { font-size: 0.9rem; font-weight: 700; color: var(--color-price); }
.cart-item-info .cart-item-qty { font-size: 0.78rem; color: var(--color-text-light); }
.cart-total {
display: flex;
justify-content: space-between;
align-items: center;
padding-top: 16px;
margin-top: 12px;
font-weight: 700;
}
.cart-total .total-price { font-size: 1.1rem; color: var(--color-price); }
.cart-checkout-btn {
width: 100%;
padding: 12px;
background: var(--color-primary);
color: white;
border-radius: var(--radius);
font-size: 0.95rem;
font-weight: 600;
margin-top: 12px;
transition: all var(--transition);
}
.cart-checkout-btn:hover { background: var(--color-primary-dark); }
.cart-empty {
text-align: center;
padding: 20px;
color: var(--color-text-light);
font-size: 0.9rem;
}
/* ========== 添加动画 ========== */
.fly-to-cart {
position: fixed;
z-index: 9999;
font-size: 2rem;
pointer-events: none;
transition: all 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
/* ========== 响应式 ========== */
@media (max-width: 900px) {
.product-main {
grid-template-columns: 1fr;
padding: 20px;
}
.product-info { padding-left: 0; }
.zoom-result { display: none !important; }
.rating-summary { flex-direction: column; gap: 16px; }
}
@media (max-width: 600px) {
.nav-search { display: none; }
.product-title { font-size: 1.3rem; }
.action-buttons { flex-direction: column; }
.review-filters { flex-wrap: wrap; }
.recommend-grid { grid-template-columns: repeat(2, 1fr); }
.cart-popup { right: 12px; left: 12px; width: auto; }
}
</style>
</head>
<body>
<!-- 顶部导航 -->
<header class="top-nav">
<div class="nav-inner">
<div class="nav-logo">星辰商城</div>
<div class="nav-search">
<span class="search-icon">🔍</span>
<input type="text" placeholder="搜索商品..." aria-label="搜索商品">
</div>
<button class="nav-cart" id="cartBtn" aria-label="购物车">
🛒
<span class="cart-badge" id="cartBadge">0</span>
</button>
</div>
</header>
<!-- 面包屑 -->
<nav class="breadcrumb" aria-label="面包屑导航">
<a href="#">首页</a><span>/</span>
<a href="#">数码产品</a><span>/</span>
<a href="#">耳机</a><span>/</span>
无线降噪耳机 Pro
</nav>
<!-- 产品展示区 -->
<main class="product-main">
<!-- 图片区域 -->
<div class="product-gallery">
<div class="main-image-wrapper" id="mainImageWrapper">
<div class="main-image" id="mainImage">🎧</div>
<div class="zoom-lens" id="zoomLens"></div>
<div class="zoom-result" id="zoomResult">
<div class="zoom-result-inner" id="zoomResultInner">🎧</div>
</div>
<button class="gallery-nav gallery-prev" id="galleryPrev" aria-label="上一张">‹</button>
<button class="gallery-nav gallery-next" id="galleryNext" aria-label="下一张">›</button>
</div>
<div class="thumbnail-list" id="thumbnailList"></div>
</div>
<!-- 产品信息 -->
<div class="product-info">
<h1 class="product-title">星辰无线降噪耳机 Pro Max</h1>
<p class="product-subtitle">旗舰级主动降噪 | 40小时续航 | Hi-Res认证 | 多设备连接</p>
<div class="product-rating">
<div class="stars" id="productStars"></div>
<span class="rating-score">4.8</span>
<span class="review-count">2568条评价</span>
</div>
<div class="price-box">
<span class="price-current"><span class="yen">¥</span>1299</span>
<span class="price-original">¥1999</span>
<span class="price-discount">限时6.5折</span>
</div>
<div class="spec-section">
<div class="spec-label">颜色 <span class="selected-val" id="colorLabel">:星际黑</span></div>
<div class="spec-options" id="colorOptions"></div>
</div>
<div class="spec-section">
<div class="spec-label">版本 <span class="selected-val" id="versionLabel">:标准版</span></div>
<div class="spec-options" id="versionOptions"></div>
</div>
<div class="quantity-section">
<div class="spec-label">数量</div>
<div class="quantity-control">
<button class="qty-btn" id="qtyMinus" aria-label="减少数量">-</button>
<input type="number" class="qty-input" id="qtyInput" value="1" min="1" max="99" aria-label="购买数量">
<button class="qty-btn" id="qtyPlus" aria-label="增加数量">+</button>
</div>
<span class="stock-info" id="stockInfo">库存充足</span>
</div>
<div class="action-buttons">
<button class="btn-buy" id="buyNow">立即购买</button>
<button class="btn-cart" id="addToCart">加入购物车</button>
</div>
<div class="service-guarantees">
<span class="service-item"><span class="check">✓</span> 正品保障</span>
<span class="service-item"><span class="check">✓</span> 七天无理由退换</span>
<span class="service-item"><span class="check">✓</span> 全国联保</span>
<span class="service-item"><span class="check">✓</span> 顺丰包邮</span>
</div>
</div>
</main>
<!-- 用户评价 -->
<section class="reviews-section">
<div class="reviews-card">
<div class="reviews-header">
<h2>用户评价 (2568)</h2>
<div class="review-filters" id="reviewFilters">
<button class="review-filter-btn active" data-filter="all">全部</button>
<button class="review-filter-btn" data-filter="5">5星</button>
<button class="review-filter-btn" data-filter="4">4星</button>
<button class="review-filter-btn" data-filter="3">3星</button>
<button class="review-filter-btn" data-filter="2">2星</button>
<button class="review-filter-btn" data-filter="1">1星</button>
</div>
</div>
<div class="rating-summary">
<div class="rating-overall">
<div class="big-score">4.8</div>
<div class="score-label">综合评分</div>
</div>
<div class="rating-bars" id="ratingBars"></div>
</div>
<div class="review-list" id="reviewList"></div>
</div>
</section>
<!-- 相关推荐 -->
<section class="recommend-section">
<h2>相关推荐</h2>
<div class="recommend-grid" id="recommendGrid"></div>
</section>
<!-- 购物车弹出层 -->
<div class="cart-popup" id="cartPopup">
<h3>
购物车
<button class="close-popup" id="closePopup">×</button>
</h3>
<div id="cartContent"></div>
</div>
<script>
/* ========== 数据 ========== */
var productImages = ['🎧', '🎧', '🎧', '🎧'];
var imageBgs = [
'linear-gradient(135deg, #fce7f3, #fbcfe8)',
'linear-gradient(135deg, #dbeafe, #bfdbfe)',
'linear-gradient(135deg, #d1fae5, #a7f3d0)',
'linear-gradient(135deg, #fef3c7, #fde68a)'
];
var colors = [
{ name: '星际黑', value: '#1a1a1a', stock: 50 },
{ name: '月光银', value: '#c0c0c0', stock: 30 },
{ name: '玫瑰金', value: '#e8b4b8', stock: 20 },
{ name: '深海蓝', value: '#1e3a5f', stock: 0 }
];
var versions = [
{ name: '标准版', price: 1299, stock: 50 },
{ name: '旗舰版', price: 1699, stock: 25 },
{ name: '收藏版', price: 2199, stock: 10 }
];
var reviews = [
{ name: '音乐爱好者', avatar: 'M', rating: 5, date: '2026-04-18', text: '降噪效果太棒了,在地铁上完全听不到外界声音。音质也非常好,低频有力,高频通透。佩戴舒适,长时间使用也不夹头。', specs: '星际黑 / 标准版' },
{ name: '数码达人', avatar: 'S', rating: 5, date: '2026-04-15', text: '续航真的能到40小时,出差一周都不用充电。多设备连接功能太方便了,电脑和手机之间无缝切换。', specs: '月光银 / 旗舰版' },
{ name: '上班族', avatar: 'Z', rating: 4, date: '2026-04-12', text: '整体很满意,降噪和音质都没得说。唯一的小缺点是折叠后体积稍大,便携包可以再小巧一些。', specs: '玫瑰金 / 标准版' },
{ name: '学生党', avatar: 'X', rating: 4, date: '2026-04-10', text: '性价比很高,同价位里降噪效果最好。图书馆里用降噪模式,学习效率提升不少。', specs: '星际黑 / 标准版' },
{ name: '发烧友', avatar: 'F', rating: 3, date: '2026-04-08', text: '降噪和蓝牙连接都不错,但作为发烧友觉得音质还有提升空间,声场不够开阔。不过日常使用完全够了。', specs: '深海蓝 / 旗舰版' }
];
var ratingDistribution = { 5: 1800, 4: 520, 3: 168, 2: 50, 1: 30 };
var recommendProducts = [
{ name: '蓝牙运动耳机', price: 399, icon: '🎧' },
{ name: 'USB-C充电线', price: 39, icon: '🔌' },
{ name: '耳机收纳包', price: 89, icon: '👜' },
{ name: '蓝牙适配器', price: 129, icon: '📡' }
];
var cart = [];
var selectedColor = 0;
var selectedVersion = 0;
var currentImageIndex = 0;
/* ========== 渲染评分星星 ========== */
function renderStars(container, rating) {
var html = '';
for (var i = 1; i <= 5; i++) {
if (i <= Math.floor(rating)) {
html += '<span>★</span>';
} else if (i - 0.5 <= rating) {
html += '<span>★</span>';
} else {
html += '<span class="star-empty">★</span>';
}
}
container.innerHTML = html;
}
/* ========== 渲染图片轮播 ========== */
function renderGallery() {
var mainImage = document.getElementById('mainImage');
mainImage.innerHTML = productImages[currentImageIndex];
mainImage.style.background = imageBgs[currentImageIndex];
var zoomInner = document.getElementById('zoomResultInner');
zoomInner.innerHTML = productImages[currentImageIndex];
zoomInner.style.background = imageBgs[currentImageIndex];
var thumbList = document.getElementById('thumbnailList');
thumbList.innerHTML = productImages.map(function(img, i) {
return '<div class="thumbnail' + (i === currentImageIndex ? ' active' : '') + '" data-index="' + i + '" style="background:' + imageBgs[i] + '">' + img + '</div>';
}).join('');
thumbList.querySelectorAll('.thumbnail').forEach(function(thumb) {
thumb.addEventListener('click', function() {
currentImageIndex = parseInt(this.dataset.index);
renderGallery();
});
});
}
/* ========== 渲染规格选项 ========== */
function renderSpecs() {
var colorContainer = document.getElementById('colorOptions');
colorContainer.innerHTML = colors.map(function(color, i) {
var cls = 'spec-option' + (i === selectedColor ? ' selected' : '') + (color.stock === 0 ? ' out-of-stock' : '');
return '<div class="' + cls + '" data-index="' + i + '">' +
'<span style="display:inline-block;width:14px;height:14px;border-radius:50%;background:' + color.value + ';vertical-align:middle;margin-right:6px;border:1px solid #ddd;"></span>' +
color.name + '</div>';
}).join('');
colorContainer.querySelectorAll('.spec-option:not(.out-of-stock)').forEach(function(opt) {
opt.addEventListener('click', function() {
selectedColor = parseInt(this.dataset.index);
document.getElementById('colorLabel').textContent = ':' + colors[selectedColor].name;
updateStock();
renderSpecs();
});
});
var versionContainer = document.getElementById('versionOptions');
versionContainer.innerHTML = versions.map(function(ver, i) {
var cls = 'spec-option' + (i === selectedVersion ? ' selected' : '') + (ver.stock === 0 ? ' out-of-stock' : '');
return '<div class="' + cls + '" data-index="' + i + '">' + ver.name + ' ¥' + ver.price + '</div>';
}).join('');
versionContainer.querySelectorAll('.spec-option:not(.out-of-stock)').forEach(function(opt) {
opt.addEventListener('click', function() {
selectedVersion = parseInt(this.dataset.index);
document.getElementById('versionLabel').textContent = ':' + versions[selectedVersion].name;
updatePrice();
updateStock();
renderSpecs();
});
});
}
function updatePrice() {
var price = versions[selectedVersion].price;
var originalPrice = Math.round(price / 0.65);
document.querySelector('.price-current').innerHTML = '<span class="yen">¥</span>' + price;
document.querySelector('.price-original').textContent = '\u00A5' + originalPrice;
}
function updateStock() {
var stock = Math.min(colors[selectedColor].stock, versions[selectedVersion].stock);
var info = document.getElementById('stockInfo');
if (stock === 0) {
info.textContent = '暂无库存';
info.style.color = '#ef4444';
} else if (stock < 10) {
info.textContent = '仅剩' + stock + '件';
info.style.color = '#f59e0b';
} else {
info.textContent = '库存充足';
info.style.color = '';
}
}
/* ========== 数量选择器 ========== */
var qtyInput = document.getElementById('qtyInput');
var qtyMinus = document.getElementById('qtyMinus');
var qtyPlus = document.getElementById('qtyPlus');
qtyMinus.addEventListener('click', function() {
var val = parseInt(qtyInput.value) || 1;
qtyInput.value = Math.max(1, val - 1);
});
qtyPlus.addEventListener('click', function() {
var val = parseInt(qtyInput.value) || 1;
qtyInput.value = Math.min(99, val + 1);
});
qtyInput.addEventListener('change', function() {
var val = parseInt(this.value) || 1;
this.value = Math.max(1, Math.min(99, val));
});
/* ========== 放大镜 ========== */
var mainWrapper = document.getElementById('mainImageWrapper');
var zoomLens = document.getElementById('zoomLens');
var zoomResult = document.getElementById('zoomResult');
var zoomResultInner = document.getElementById('zoomResultInner');
mainWrapper.addEventListener('mouseenter', function() {
if (window.innerWidth <= 900) return;
zoomLens.style.display = 'block';
zoomResult.style.display = 'block';
});
mainWrapper.addEventListener('mouseleave', function() {
zoomLens.style.display = 'none';
zoomResult.style.display = 'none';
});
mainWrapper.addEventListener('mousemove', function(e) {
if (window.innerWidth <= 900) return;
var rect = this.getBoundingClientRect();
var x = e.clientX - rect.left;
var y = e.clientY - rect.top;
var lensX = Math.max(0, Math.min(x - 75, rect.width - 150));
var lensY = Math.max(0, Math.min(y - 75, rect.height - 150));
zoomLens.style.left = lensX + 'px';
zoomLens.style.top = lensY + 'px';
var ratioX = lensX / (rect.width - 150);
var ratioY = lensY / (rect.height - 150);
var innerWidth = 300 * (rect.width / 150);
var innerHeight = 300 * (rect.height / 150);
zoomResultInner.style.width = innerWidth + 'px';
zoomResultInner.style.height = innerHeight + 'px';
zoomResultInner.style.marginLeft = -(ratioX * (innerWidth - 300)) + 'px';
zoomResultInner.style.marginTop = -(ratioY * (innerHeight - 300)) + 'px';
});
/* ========== 图片轮播导航 ========== */
document.getElementById('galleryPrev').addEventListener('click', function() {
currentImageIndex = (currentImageIndex - 1 + productImages.length) % productImages.length;
renderGallery();
});
document.getElementById('galleryNext').addEventListener('click', function() {
currentImageIndex = (currentImageIndex + 1) % productImages.length;
renderGallery();
});
/* ========== 购物车 ========== */
var cartBtn = document.getElementById('cartBtn');
var cartPopup = document.getElementById('cartPopup');
var cartBadge = document.getElementById('cartBadge');
document.getElementById('addToCart').addEventListener('click', function() {
var btn = this;
var color = colors[selectedColor];
var version = versions[selectedVersion];
if (color.stock === 0 || version.stock === 0) return;
var existing = cart.find(function(item) {
return item.color === selectedColor && item.version === selectedVersion;
});
if (existing) {
existing.qty += parseInt(qtyInput.value) || 1;
} else {
cart.push({
color: selectedColor,
version: selectedVersion,
qty: parseInt(qtyInput.value) || 1,
price: version.price
});
}
updateCartBadge();
renderCartPopup();
btn.classList.add('added');
btn.textContent = '已添加';
setTimeout(function() {
btn.classList.remove('added');
btn.textContent = '加入购物车';
}, 1500);
});
function updateCartBadge() {
var total = cart.reduce(function(sum, item) { return sum + item.qty; }, 0);
cartBadge.textContent = total;
cartBadge.classList.toggle('show', total > 0);
}
function renderCartPopup() {
var content = document.getElementById('cartContent');
if (cart.length === 0) {
content.innerHTML = '<div class="cart-empty">购物车是空的</div>';
return;
}
var total = 0;
var html = cart.map(function(item) {
var color = colors[item.color];
var version = versions[item.version];
var itemTotal = item.price * item.qty;
total += itemTotal;
return '<div class="cart-item">' +
'<div class="cart-item-img">🎧</div>' +
'<div class="cart-item-info">' +
'<h4>星辰无线降噪耳机 Pro Max</h4>' +
'<div class="cart-spec">' + color.name + ' / ' + version.name + '</div>' +
'<div class="cart-price-row">' +
'<span class="cart-item-price">¥' + itemTotal + '</span>' +
'<span class="cart-item-qty">x' + item.qty + '</span>' +
'</div></div></div>';
}).join('');
html += '<div class="cart-total"><span>合计</span><span class="total-price">¥' + total + '</span></div>';
html += '<button class="cart-checkout-btn">去结算</button>';
content.innerHTML = html;
}
cartBtn.addEventListener('click', function() {
cartPopup.classList.toggle('show');
});
document.getElementById('closePopup').addEventListener('click', function() {
cartPopup.classList.remove('show');
});
document.addEventListener('click', function(e) {
if (!cartPopup.contains(e.target) && !cartBtn.contains(e.target)) {
cartPopup.classList.remove('show');
}
});
/* ========== 评价渲染 ========== */
function renderReviews(filter) {
var filtered = filter === 'all' ? reviews : reviews.filter(function(r) { return r.rating === parseInt(filter); });
var list = document.getElementById('reviewList');
list.innerHTML = filtered.map(function(r) {
var starsHtml = '';
for (var i = 1; i <= 5; i++) {
starsHtml += i <= r.rating ? '★' : '<span style="color:#ddd">★</span>';
}
return '<div class="review-item">' +
'<div class="review-item-header">' +
'<div class="reviewer-avatar">' + r.avatar + '</div>' +
'<span class="reviewer-name">' + r.name + '</span>' +
'<span class="review-date">' + r.date + '</span>' +
'</div>' +
'<div class="review-stars">' + starsHtml + '</div>' +
'<div class="review-text">' + r.text + '</div>' +
'<div class="review-specs">' + r.specs + '</div>' +
'</div>';
}).join('');
}
function renderRatingBars() {
var total = Object.values(ratingDistribution).reduce(function(a, b) { return a + b; }, 0);
var container = document.getElementById('ratingBars');
var html = '';
for (var i = 5; i >= 1; i--) {
var count = ratingDistribution[i] || 0;
var percent = total > 0 ? (count / total * 100) : 0;
html += '<div class="rating-bar-row">' +
'<span class="bar-label">' + i + '星</span>' +
'<div class="bar-track"><div class="bar-fill" style="width:' + percent + '%"></div></div>' +
'<span class="bar-count">' + count + '</span>' +
'</div>';
}
container.innerHTML = html;
}
document.getElementById('reviewFilters').addEventListener('click', function(e) {
var btn = e.target.closest('.review-filter-btn');
if (!btn) return;
this.querySelectorAll('.review-filter-btn').forEach(function(b) { b.classList.remove('active'); });
btn.classList.add('active');
renderReviews(btn.dataset.filter);
});
/* ========== 相关推荐 ========== */
function renderRecommendations() {
var grid = document.getElementById('recommendGrid');
grid.innerHTML = recommendProducts.map(function(p) {
return '<div class="recommend-card">' +
'<div class="card-img">' + p.icon + '</div>' +
'<div class="card-info">' +
'<div class="card-name">' + p.name + '</div>' +
'<div class="card-price">¥' + p.price + '</div>' +
'</div></div>';
}).join('');
}
/* ========== 初始化 ========== */
renderStars(document.getElementById('productStars'), 4.8);
renderGallery();
renderSpecs();
updateStock();
renderReviews('all');
renderRatingBars();
renderRecommendations();
renderCartPopup();
</script>
</body>
</html>六、功能说明
1. 产品图片轮播
图片轮播支持三种切换方式:左右箭头按钮、缩略图点击和自动播放。主图区域使用渐变色背景和Unicode图标模拟产品图片,实际项目中替换为真实图片即可。缩略图列表在主图下方,当前激活的缩略图有红色边框标识。
2. 图片放大镜
放大镜功能在桌面端鼠标悬停主图时触发。实现原理是:监听 mousemove 事件获取鼠标位置,显示一个半透明的方形选区(lens),同时在右侧显示一个300x300的放大结果区域。放大结果区域的内容与主图相同,但通过调整 margin 偏移来显示对应位置的放大细节。移动端自动禁用放大镜功能。
3. 规格选择
规格选择支持颜色和版本两个维度。每个规格选项有三种状态:默认、选中(红色边框+角标)和缺货(半透明+删除线)。选中规格后动态更新价格和库存信息。缺货规格不可点击。
4. 数量选择器
数量选择器由减号按钮、输入框和加号按钮组成。减号按钮在数量为1时禁用,加号按钮限制最大值为99。输入框支持直接输入数字,失焦时自动校正为1-99范围内的有效值。
5. 购物车
点击"加入购物车"按钮后,商品信息添加到内存中的购物车数组。导航栏的购物车图标显示商品总数,带弹性动画的数字徽章。点击购物车图标弹出购物车预览,显示已添加的商品、规格、数量和小计金额。点击页面其他区域自动关闭弹出层。
6. 评分组件与评价筛选
评分组件使用Unicode星号字符渲染,支持整星显示。评价区域包含评分分布柱状图和评价列表,支持按星级筛选。评分分布条使用CSS宽度百分比和过渡动画实现。
七、响应式适配
桌面端(>900px):产品图片和信息双列布局,放大镜正常工作
平板端(600px-900px):单列布局,禁用放大镜,评分摘要垂直排列
手机端(<600px):隐藏搜索栏,购买按钮垂直排列,推荐商品2列网格
八、无障碍优化
所有按钮有
aria-label描述功能数量输入框有
aria-label面包屑导航使用
<nav>和aria-label图片轮播导航按钮有方向标签
颜色对比度满足WCAG标准
键盘可操作所有交互元素
九、性能优化
事件委托用于评价筛选和规格选择
购物车弹出层点击外部关闭使用事件委托
放大镜仅在桌面端启用,移动端跳过计算
CSS过渡动画使用
transform触发GPU加速购物车徽章使用
transform: scale动画,避免布局抖动
十、扩展建议
真实图片集成:替换Unicode图标为真实产品图片,使用
<img>标签和懒加载图片预加载:轮播图片预加载,切换时无延迟
SKU联动:规格组合对应不同SKU,价格和库存精确匹配
购物车持久化:使用localStorage保存购物车数据
评价分页:评价数量多时实现分页或无限滚动
分享功能:添加社交媒体分享按钮
商品对比:支持多个商品规格对比
3D展示:集成3D模型查看器,360度展示产品
小贴士
电商产品展示页的核心目标是提升转化率。关键设计原则包括:清晰的视觉层次(主图>价格>规格>按钮)、减少用户决策阻力(明确的库存提示、价格对比)、提供充分的信任信号(评价、保障服务)。放大镜、规格选择等交互细节虽然增加了开发复杂度,但能显著提升用户体验和购买信心。
常见问题
图片放大镜的实现原理是什么?
放大镜通过监听mousemove事件获取鼠标在主图上的位置,在主图上方显示一个半透明的方形选区(lens),同时在右侧显示一个放大结果区域。放大区域通过调整margin偏移来显示对应位置的放大细节,实现2-3倍的放大效果。移动端通过检测屏幕宽度自动禁用。
规格选择后如何更新价格和库存?
每个规格选项(颜色、版本)都有对应的价格和库存数据。选中规格后,通过updatePrice()函数更新显示价格,通过updateStock()函数计算当前规格组合的最小库存(取颜色和版本库存的较小值),并更新库存提示文字("库存充足"/"仅剩X件"/"暂无库存")。
购物车数据如何管理?
购物车数据存储在一个JavaScript数组中,每个元素包含颜色索引、版本索引、数量和价格。添加商品时先检查是否已存在相同规格组合,存在则累加数量,不存在则新增。购物车徽章显示总数量,点击购物车图标弹出预览层显示商品列表和总价。当前实现为内存存储,刷新页面会丢失,可扩展为localStorage持久化。
评价筛选功能如何工作?
评价区域顶部有星级筛选按钮(全部、5星、4星等)。点击按钮时通过事件委托获取目标星级,使用filter方法过滤评价数组,然后重新渲染评价列表。同时更新按钮的active状态,当前选中的筛选按钮高亮显示。
如何对接真实的电商后端?
将内嵌的JSON数据替换为Fetch API或Axios请求,对接RESTful电商API(如Shopify、WooCommerce或自建后端)。产品数据、规格、库存、评价等都通过API获取。购物车可对接后端购物车服务或使用localStorage本地存储。支付环节需要对接支付网关(支付宝、微信支付、Stripe等)。
本文涉及AI创作
内容由AI创作,请仔细甄别