1354 lines
41 KiB
Markdown
1354 lines
41 KiB
Markdown
|
|
# 无标题
|
|||
|
|
|
|||
|
|
# 一、项目背景
|
|||
|
|
|
|||
|
|
在电子商务快速发展的环境下,购物网站已成为消费者获取商品与完成交易的主要平台。相比于后台功能的稳定性,前端展示页面直接决定了用户的第一印象与购物体验,是影响转化率与复购率的关键环节。
|
|||
|
|
|
|||
|
|
- 当前电商竞争激烈,用户浏览习惯趋向于 **快速、直观、便捷**,因此前端页面需同时满足 **美观性、交互性与响应速度**;
|
|||
|
|
- 消费者群体覆盖 **PC、平板、手机等多终端设备**,页面需要良好的适配性与响应式布局;
|
|||
|
|
- 在购物场景中,商品展示不仅是图片与文字的堆砌,还需要借助 **分类导航、筛选搜索、商品详情、购物车交互** 等功能,提升浏览效率与用户留存度。
|
|||
|
|
|
|||
|
|
本项目的开发对象是一家虚拟购物平台的前端展示页面,目标是构建一个 **界面友好、功能完善、跨平台适配** 的购物网站原型,作为前端开发与电商运营课程的综合实践案例。
|
|||
|
|
|
|||
|
|
# 二、项目核心目标
|
|||
|
|
|
|||
|
|
1. **首页展示**
|
|||
|
|
- 提供导航栏(分类、购物车、用户中心、登录注册入口);
|
|||
|
|
- 首页 banner 轮播,突出推荐商品或促销活动;
|
|||
|
|
- 商品卡片式展示,包含图片、名称、价格、加入购物车按钮。
|
|||
|
|
2. **商品分类与搜索**
|
|||
|
|
- 分类导航:支持多级分类(如服饰 > 女装 > 外套);
|
|||
|
|
- 搜索框:支持关键词查询,并返回相关商品列表;
|
|||
|
|
- 筛选功能:支持价格区间、品牌、销量等条件。
|
|||
|
|
3. **商品详情页**
|
|||
|
|
- 展示高清图片、价格、库存、规格参数、用户评价;
|
|||
|
|
- 具备数量选择与“加入购物车”按钮;
|
|||
|
|
- 支持图片放大查看与规格切换。
|
|||
|
|
4. **购物车与结算**
|
|||
|
|
- 用户可在购物车查看所选商品、修改数量、删除条目;
|
|||
|
|
- 提供合计金额显示与“去结算”按钮;
|
|||
|
|
- 页面需动态更新购物车商品数量。
|
|||
|
|
5. **用户交互与体验**
|
|||
|
|
- 页面需支持响应式布局(兼容手机、平板、PC);
|
|||
|
|
- 保持加载速度快,页面跳转流畅;
|
|||
|
|
- 提供基础交互提示(如 hover 效果、按钮点击反馈)。
|
|||
|
|
6. **技术要求**
|
|||
|
|
- 前端框架:HTML5 + CSS3 + JavaScript(可扩展 React/Vue 等框架);
|
|||
|
|
- 样式:支持组件化与可复用样式,页面结构清晰;
|
|||
|
|
- 动态效果:支持简单动画(如轮播图、按钮 hover 过渡)。
|
|||
|
|
|
|||
|
|
# 三、项目需求与功能模块分解
|
|||
|
|
|
|||
|
|
为确保购物网站前端展示页面设计逻辑完整、交互合理,需要将核心业务流程拆解,输入的提示词如下:
|
|||
|
|
|
|||
|
|
```markdown
|
|||
|
|
我需要做一个购物网站,现在需要你输出这个项目的需求,并且把功能板块拆解开来;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
得到的结果(功能模块)如下:
|
|||
|
|
|
|||
|
|
## 1. 用户输入行为
|
|||
|
|
|
|||
|
|
| **用户操作** | **说明** |
|
|||
|
|
| --- | --- |
|
|||
|
|
| 点击首页导航栏 | 用户在首页选择分类、购物车、个人中心等入口 |
|
|||
|
|
| 搜索框输入关键词 | 用户输入商品名称/品牌并提交查询 |
|
|||
|
|
| 筛选/排序操作 | 用户根据价格区间、销量、人气等进行筛选或排序 |
|
|||
|
|
| 点击商品卡片 | 用户点击商品卡片进入详情页 |
|
|||
|
|
| 在详情页选择规格/数量 | 用户选择商品型号、颜色、数量等 |
|
|||
|
|
| 点击“加入购物车”按钮 | 将所选商品加入购物车 |
|
|||
|
|
| 在购物车修改商品数量 | 增加/减少数量或删除商品 |
|
|||
|
|
| 点击“去结算”按钮 | 进入结算/支付页面 |
|
|||
|
|
| 用户登录/注册 | 输入账号、密码或注册新用户 |
|
|||
|
|
| 查看订单历史 | 在个人中心查看已下单的订单列表 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. 系统输出反馈
|
|||
|
|
|
|||
|
|
| **页面反馈** | **说明** |
|
|||
|
|
| --- | --- |
|
|||
|
|
| 渲染首页商品列表 | 展示推荐商品、促销 banner 与分类入口 |
|
|||
|
|
| 返回搜索结果 | 根据关键词渲染商品列表 |
|
|||
|
|
| 更新筛选/排序结果 | 按条件刷新商品展示内容 |
|
|||
|
|
| 展示商品详情 | 显示高清图片、价格、库存、评价、规格 |
|
|||
|
|
| 更新购物车图标 | 动态显示购物车商品数量 |
|
|||
|
|
| 渲染购物车列表 | 展示已选商品、数量、金额合计 |
|
|||
|
|
| 生成结算页面 | 显示收货信息、支付金额、支付方式 |
|
|||
|
|
| 验证用户登录状态 | 成功则进入个人中心,失败则提示错误 |
|
|||
|
|
| 展示订单历史 | 渲染用户过往订单及物流状态 |
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. 功能模块划分
|
|||
|
|
|
|||
|
|
- **首页模块**:商品展示、促销轮播、分类导航。
|
|||
|
|
- **搜索与分类模块**:关键词搜索、多条件筛选与排序。
|
|||
|
|
- **商品详情模块**:商品图片、规格、评价与加入购物车功能。
|
|||
|
|
- **购物车模块**:商品数量调整、合计金额计算、删除功能。
|
|||
|
|
- **结算与支付模块**:收货地址、支付金额确认、支付方式选择。
|
|||
|
|
- **用户登录/注册模块**:账号登录、注册与状态验证。
|
|||
|
|
- **个人中心模块**:订单历史、收货地址管理、账号设置。
|
|||
|
|
|
|||
|
|
# 四、项目开发逻辑说明
|
|||
|
|
|
|||
|
|
项目开发逻辑说明的核心作用在于为参与者奠定一条清晰、共享的思考主线,把零散任务串成可验证、可复现、可迭代的决策路径,确保进度、成本和质量始终围绕最初商业目标递进,最终实现价值交付与知识沉淀的双赢。
|
|||
|
|
|
|||
|
|
输入给ChatGpt的提示词及输出结果如下:
|
|||
|
|
|
|||
|
|
```markdown
|
|||
|
|
输出这个项目的开发逻辑说明
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
1. **整体导航与页面切换逻辑**
|
|||
|
|
- 用户通过首页顶部导航栏进入各模块页面(首页、分类、购物车、个人中心)。
|
|||
|
|
- 所有页面切换保持统一的路由规则(如 `home → detail → cart → checkout`),并通过前端路由实现无刷新跳转。
|
|||
|
|
- 页面在切换时需保留用户状态(如登录状态、购物车数量),避免信息丢失。
|
|||
|
|
2. **首页与商品展示逻辑**
|
|||
|
|
- 首页加载时,通过接口获取推荐商品与轮播图信息,渲染到商品卡片区。
|
|||
|
|
- 用户点击分类入口或搜索框时,跳转到商品分类/搜索结果页面。
|
|||
|
|
- “加入购物车”按钮点击后,实时调用购物车更新逻辑,并在页面顶部动态刷新购物车图标数量。
|
|||
|
|
3. **搜索与筛选逻辑**
|
|||
|
|
- 用户在搜索框输入关键词并提交,系统调用商品数据接口,返回符合条件的商品列表。
|
|||
|
|
- 筛选条件(如价格区间、销量、评分)变化时,页面自动刷新商品结果并保持搜索关键词不变。
|
|||
|
|
- 排序选项(价格升序、销量优先)通过前端逻辑控制数据展示顺序,保证结果直观可读。
|
|||
|
|
4. **商品详情逻辑**
|
|||
|
|
- 用户点击商品卡片进入详情页,页面需渲染商品高清图、价格、库存、评价等详细信息。
|
|||
|
|
- 规格选择逻辑:点击不同的规格选项,价格和库存信息实时更新。
|
|||
|
|
- “加入购物车”按钮触发购物车数据更新,若用户未登录,则提示登录。
|
|||
|
|
5. **购物车逻辑**
|
|||
|
|
- 加入购物车后,购物车页面渲染所有选中商品的名称、价格、数量、合计金额。
|
|||
|
|
- 用户可在购物车修改数量或删除商品,页面需实时更新总金额。
|
|||
|
|
- 点击“去结算”按钮后,校验用户是否登录;若未登录,跳转到登录页面;若已登录,则进入结算页面。
|
|||
|
|
6. **结算与支付逻辑**
|
|||
|
|
- 结算页面需展示用户收货信息、支付金额明细、选择支付方式入口。
|
|||
|
|
- 用户点击“确认支付”后,模拟生成订单,并跳转到订单成功页。
|
|||
|
|
- 若支付失败或取消,系统提示并返回购物车。
|
|||
|
|
7. **用户登录/注册逻辑**
|
|||
|
|
- 用户登录:输入账号密码,验证通过后存储登录状态(本地存储或 session)。
|
|||
|
|
- 用户注册:填写必要信息(用户名、邮箱/手机号、密码),完成后自动跳转到登录页面。
|
|||
|
|
- 登录状态需在所有页面全局生效,并影响购物车、个人中心等功能的可用性。
|
|||
|
|
8. **个人中心逻辑**
|
|||
|
|
- 登录用户可在个人中心查看历史订单、账户信息、收货地址。
|
|||
|
|
- 点击历史订单可进入订单详情页,查看支付状态与物流信息。
|
|||
|
|
- 支持用户修改基本资料与退出登录操作。
|
|||
|
|
|
|||
|
|
# 五、重要注意事项与关键点补充
|
|||
|
|
|
|||
|
|
让AI代替开发者的思考学习过程,询问项目开发的重要部分内容可以弥补开发者经验不足的问题,并且可以保障项目质量。
|
|||
|
|
|
|||
|
|
输入给ChatGpt的提示词及输出结果如下:
|
|||
|
|
|
|||
|
|
```markdown
|
|||
|
|
这个项目有什么需要我注意的地方?
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
1. **页面一致性与可用性**
|
|||
|
|
- 所有页面(首页、分类、详情、购物车、结算、个人中心)必须采用统一的导航栏与页脚设计,保证用户无论在哪个页面都能快速返回首页或进入购物车。
|
|||
|
|
- 保证移动端与PC端的样式一致性,响应式布局必须覆盖主流分辨率(≥320px 的手机屏幕到 ≥1920px 的桌面屏幕)。
|
|||
|
|
2. **数据交互与状态管理**
|
|||
|
|
- 购物车、登录状态、订单信息等关键数据需统一管理,避免因刷新或页面切换导致数据丢失。
|
|||
|
|
- 推荐使用本地存储(localStorage/sessionStorage)或前端状态管理工具(如 Redux/Vuex)来保证状态同步。
|
|||
|
|
3. **用户体验优化**
|
|||
|
|
- 搜索和筛选需设置防抖/节流,避免频繁请求导致性能下降。
|
|||
|
|
- 商品图片需支持懒加载,提升页面加载速度。
|
|||
|
|
- 在购物流程中,每个关键动作(加入购物车、提交订单、支付确认)必须有明确的视觉反馈。
|
|||
|
|
4. **安全性与合规性**
|
|||
|
|
- 登录/注册输入框需有前端校验(如密码长度≥6位、邮箱格式正确)。
|
|||
|
|
- 支付流程可先模拟,但必须预留安全接口,后续接入第三方支付时保证合规。
|
|||
|
|
- 避免在前端暴露敏感信息(如用户密码、支付密钥),所有敏感校验必须在后端完成。
|
|||
|
|
5. **性能与兼容性**
|
|||
|
|
- CSS、JS 文件需压缩打包,减少首屏加载时间。
|
|||
|
|
- 图片需使用合适格式(如 WebP、JPEG 压缩)保证清晰度与加载速度的平衡。
|
|||
|
|
- 必须兼容主流浏览器(Chrome、Firefox、Safari、Edge)及常用手机浏览器(微信内置浏览器、UC、QQ 浏览器)。
|
|||
|
|
6. **常见易错点提醒**
|
|||
|
|
- **购物车数量更新异常**:常见问题是修改数量后金额未实时更新,需要双向绑定逻辑。
|
|||
|
|
- **登录状态丢失**:若只保存在内存中,刷新页面会丢失,应写入本地存储。
|
|||
|
|
- **结算金额不一致**:前端显示金额必须与后端订单生成金额一致,避免用户体验差或纠纷。
|
|||
|
|
- **响应式缺陷**:仅在PC端测试,可能导致移动端显示错乱,需逐屏测试。
|
|||
|
|
|
|||
|
|
# 六、页面结构与交互流程图
|
|||
|
|
|
|||
|
|
页面结构与交互流程图将抽象需求转译为“可视化蓝图”,以节点连线清晰呈现信息层级、页面关系、操作路径与状态反馈,使产品、设计、开发、测试四方在同一幅图里快速对齐认知、发现断点与冗余。
|
|||
|
|
|
|||
|
|
输入给ChatGpt的提示词及输出结果如下:
|
|||
|
|
|
|||
|
|
```markdown
|
|||
|
|
给我这个项目的结构框架和用户交互流程(文字版)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 1. 页面结构图
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
首页(Home)
|
|||
|
|
│
|
|||
|
|
├── 商品分类页(Category)
|
|||
|
|
│ ├── 分类列表
|
|||
|
|
│ ├── 筛选条件
|
|||
|
|
│ └── 排序选项
|
|||
|
|
│
|
|||
|
|
├── 搜索结果页(Search Result)
|
|||
|
|
│ ├── 搜索框
|
|||
|
|
│ ├── 商品列表
|
|||
|
|
│ └── 筛选/排序功能
|
|||
|
|
│
|
|||
|
|
├── 商品详情页(Product Detail)
|
|||
|
|
│ ├── 商品图片展示
|
|||
|
|
│ ├── 规格参数选择
|
|||
|
|
│ ├── 用户评价
|
|||
|
|
│ └── 加入购物车按钮
|
|||
|
|
│
|
|||
|
|
├── 购物车页(Cart)
|
|||
|
|
│ ├── 已选商品列表
|
|||
|
|
│ ├── 数量修改与删除
|
|||
|
|
│ └── 去结算按钮
|
|||
|
|
│
|
|||
|
|
├── 结算/支付页(Checkout/Payment)
|
|||
|
|
│ ├── 收货信息
|
|||
|
|
│ ├── 支付方式选择
|
|||
|
|
│ └── 订单确认
|
|||
|
|
│
|
|||
|
|
├── 订单成功页(Order Success)
|
|||
|
|
│ └── 返回首页 / 查看订单按钮
|
|||
|
|
│
|
|||
|
|
├── 用户登录/注册页(Login/Register)
|
|||
|
|
│ ├── 登录表单
|
|||
|
|
│ └── 注册表单
|
|||
|
|
│
|
|||
|
|
└── 个人中心页(User Center)
|
|||
|
|
├── 历史订单
|
|||
|
|
├── 收货地址管理
|
|||
|
|
└── 账号信息设置
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. 用户交互流程图
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
用户进入首页
|
|||
|
|
↓
|
|||
|
|
浏览推荐商品 / 选择分类 / 搜索商品
|
|||
|
|
↓
|
|||
|
|
商品列表展示(分类页 / 搜索结果页)
|
|||
|
|
↓
|
|||
|
|
点击商品 → 进入商品详情页
|
|||
|
|
↓
|
|||
|
|
选择规格、数量 → 点击“加入购物车”
|
|||
|
|
↓
|
|||
|
|
进入购物车页
|
|||
|
|
↓
|
|||
|
|
调整数量 / 删除商品 → 点击“去结算”
|
|||
|
|
↓
|
|||
|
|
结算页(需登录验证)
|
|||
|
|
↓
|
|||
|
|
[未登录] → 跳转登录/注册页 → 登录成功返回结算
|
|||
|
|
[已登录] → 填写收货信息 → 选择支付方式 → 确认订单
|
|||
|
|
↓
|
|||
|
|
支付成功 → 跳转订单成功页
|
|||
|
|
↓
|
|||
|
|
用户可选择:
|
|||
|
|
- 返回首页继续购物
|
|||
|
|
- 前往个人中心查看订单历史
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
# 七、常见错误与优化建议
|
|||
|
|
|
|||
|
|
1. **页面跳转状态丢失**
|
|||
|
|
- **错误表现**:用户从首页进入商品详情或购物车时,登录状态或购物车数据丢失,导致需要重复登录或重新选择商品。
|
|||
|
|
- **原因分析**:缺乏统一的状态管理,仅在页面级别存储用户信息。
|
|||
|
|
- **优化建议**:使用本地存储(LocalStorage/SessionStorage)或前端状态管理(Redux/Vuex),保证数据在多页面间持久化。
|
|||
|
|
2. **购物车更新不同步**
|
|||
|
|
- **错误表现**:用户在详情页加入购物车后,购物车图标数量未更新,或购物车页面数据与实际不一致。
|
|||
|
|
- **原因分析**:购物车数据修改后未触发全局刷新,或接口调用与渲染逻辑未绑定。
|
|||
|
|
- **优化建议**:建立购物车数据的统一更新方法,并在更新后触发全局状态变化,保证所有组件同步响应。
|
|||
|
|
3. **响应式布局缺陷**
|
|||
|
|
- **错误表现**:网站在手机端或平板端出现内容溢出、按钮错位、文字遮挡等问题。
|
|||
|
|
- **原因分析**:页面仅针对 PC 端设计,未充分考虑不同分辨率适配。
|
|||
|
|
- **优化建议**:采用响应式框架(Bootstrap、Tailwind CSS)或媒体查询,逐屏测试常见设备分辨率。
|
|||
|
|
4. **商品搜索与筛选性能低下**
|
|||
|
|
- **错误表现**:用户在搜索框输入或筛选条件切换时,页面卡顿或频繁刷新。
|
|||
|
|
- **原因分析**:没有设置防抖/节流,导致过多请求同时发出。
|
|||
|
|
- **优化建议**:对搜索/筛选操作设置防抖(300ms 左右),减少请求次数,同时对返回结果做缓存以提升性能。
|
|||
|
|
5. **结算金额与订单金额不一致**
|
|||
|
|
- **错误表现**:结算页面显示的总金额与订单提交后生成的金额不同,容易引发纠纷。
|
|||
|
|
- **原因分析**:仅在前端计算金额,缺乏与后端的校验逻辑。
|
|||
|
|
- **优化建议**:金额计算应以前端展示为主,但最终以后台返回金额为准,前端需同步展示后端的确认金额。
|
|||
|
|
6. **安全校验缺失**
|
|||
|
|
- **错误表现**:登录表单可输入无效账号,或结算时可提交空收货地址。
|
|||
|
|
- **原因分析**:缺少前端输入验证逻辑。
|
|||
|
|
- **优化建议**:在前端增加正则验证(如密码长度、邮箱格式、地址非空),并结合后端二次校验,避免恶意输入。
|
|||
|
|
7. **图片加载过慢**
|
|||
|
|
- **错误表现**:商品图片清晰度高,但页面加载时间过长,用户等待体验差。
|
|||
|
|
- **原因分析**:未进行图片压缩与懒加载。
|
|||
|
|
- **优化建议**:采用 WebP 等高效格式,结合懒加载(仅当图片进入视口时才加载)。
|
|||
|
|
|
|||
|
|
# 八、项目开发阶段
|
|||
|
|
|
|||
|
|
项目具体开发阶段,可以在项目架构清晰的前提下,向AI输出具体的描述需求及要求文字,用AI辅助生成代码,供开发者参考与使用。
|
|||
|
|
|
|||
|
|
输入给ChatGpt的提示词及输出结果如下:
|
|||
|
|
|
|||
|
|
```markdown
|
|||
|
|
基于以上内容的聊天记录和网页开发的一般流程,分板块输出符合我要求的具体代码,并且要完整、细致、可供我直接黏贴复制。
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 1. 公共脚本
|
|||
|
|
|
|||
|
|
```jsx
|
|||
|
|
/**
|
|||
|
|
* 公共方法库 - common.js
|
|||
|
|
* 提供购物车管理、订单管理、工具函数等功能
|
|||
|
|
* 所有页面均可调用
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
//////////////////// 工具函数 ////////////////////
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 格式化价格(保留两位小数,前缀¥)
|
|||
|
|
* @param {number} price
|
|||
|
|
* @returns {string}
|
|||
|
|
*/
|
|||
|
|
function formatPrice(price) {
|
|||
|
|
return "¥" + price.toFixed(2);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//////////////////// 购物车相关 ////////////////////
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取购物车
|
|||
|
|
* @returns {Array}
|
|||
|
|
*/
|
|||
|
|
function getCart() {
|
|||
|
|
return JSON.parse(localStorage.getItem("cart")) || [];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 保存购物车
|
|||
|
|
* @param {Array} cart
|
|||
|
|
*/
|
|||
|
|
function saveCart(cart) {
|
|||
|
|
localStorage.setItem("cart", JSON.stringify(cart));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 清空购物车
|
|||
|
|
*/
|
|||
|
|
function clearCart() {
|
|||
|
|
localStorage.removeItem("cart");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 添加商品到购物车
|
|||
|
|
* @param {Object} product - 商品对象
|
|||
|
|
* @param {number} quantity - 数量
|
|||
|
|
*/
|
|||
|
|
function addToCart(product, quantity = 1) {
|
|||
|
|
let cart = getCart();
|
|||
|
|
const index = cart.findIndex(item => item.id === product.id && item.spec === product.spec);
|
|||
|
|
|
|||
|
|
if (index > -1) {
|
|||
|
|
cart[index].quantity += quantity;
|
|||
|
|
} else {
|
|||
|
|
cart.push({ ...product, quantity });
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
saveCart(cart);
|
|||
|
|
alert("已加入购物车!");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 从购物车中删除商品
|
|||
|
|
* @param {number} index - 商品在购物车中的索引
|
|||
|
|
*/
|
|||
|
|
function removeFromCart(index) {
|
|||
|
|
let cart = getCart();
|
|||
|
|
if (index > -1) {
|
|||
|
|
cart.splice(index, 1);
|
|||
|
|
saveCart(cart);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//////////////////// 订单相关 ////////////////////
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 获取订单列表
|
|||
|
|
* @returns {Array}
|
|||
|
|
*/
|
|||
|
|
function getOrders() {
|
|||
|
|
return JSON.parse(localStorage.getItem("orders")) || [];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 保存订单
|
|||
|
|
* @param {Array} orders
|
|||
|
|
*/
|
|||
|
|
function saveOrders(orders) {
|
|||
|
|
localStorage.setItem("orders", JSON.stringify(orders));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 添加新订单
|
|||
|
|
* @param {Object} order
|
|||
|
|
*/
|
|||
|
|
function addOrder(order) {
|
|||
|
|
let orders = getOrders();
|
|||
|
|
orders.push(order);
|
|||
|
|
saveOrders(orders);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//////////////////// 导航高亮(可选) ////////////////////
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 页面导航高亮处理
|
|||
|
|
* 在每个页面的 <nav> 中给当前页面加高亮样式
|
|||
|
|
*/
|
|||
|
|
function highlightNav() {
|
|||
|
|
const path = window.location.pathname.split("/").pop();
|
|||
|
|
const links = document.querySelectorAll("nav a");
|
|||
|
|
|
|||
|
|
links.forEach(link => {
|
|||
|
|
if (link.getAttribute("href") === path) {
|
|||
|
|
link.style.fontWeight = "bold";
|
|||
|
|
link.style.color = "#e91e63";
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 页面加载完成后自动执行高亮
|
|||
|
|
document.addEventListener("DOMContentLoaded", highlightNav);
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 2. 购物网站首页的基础框架代码
|
|||
|
|
|
|||
|
|
```html
|
|||
|
|
<!DOCTYPE html>
|
|||
|
|
<html lang="zh-CN">
|
|||
|
|
<head>
|
|||
|
|
<meta charset="UTF-8">
|
|||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|||
|
|
<title>购物网站首页</title>
|
|||
|
|
<style>
|
|||
|
|
/* 基础样式 */
|
|||
|
|
body {
|
|||
|
|
font-family: Arial, sans-serif;
|
|||
|
|
margin: 0;
|
|||
|
|
padding: 0;
|
|||
|
|
background-color: #f5f5f5;
|
|||
|
|
}
|
|||
|
|
header {
|
|||
|
|
background-color: #333;
|
|||
|
|
color: #fff;
|
|||
|
|
padding: 15px;
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
align-items: center;
|
|||
|
|
}
|
|||
|
|
header h1 {
|
|||
|
|
margin: 0;
|
|||
|
|
font-size: 20px;
|
|||
|
|
}
|
|||
|
|
nav a {
|
|||
|
|
color: #fff;
|
|||
|
|
margin-left: 20px;
|
|||
|
|
text-decoration: none;
|
|||
|
|
}
|
|||
|
|
nav a:hover {
|
|||
|
|
text-decoration: underline;
|
|||
|
|
}
|
|||
|
|
.banner {
|
|||
|
|
width: 100%;
|
|||
|
|
height: 250px;
|
|||
|
|
background: url('https://picsum.photos/1200/250?random=1') no-repeat center;
|
|||
|
|
background-size: cover;
|
|||
|
|
}
|
|||
|
|
.product-list {
|
|||
|
|
display: grid;
|
|||
|
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|||
|
|
gap: 20px;
|
|||
|
|
padding: 20px;
|
|||
|
|
}
|
|||
|
|
.product-card {
|
|||
|
|
background: #fff;
|
|||
|
|
border-radius: 5px;
|
|||
|
|
padding: 10px;
|
|||
|
|
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
|
|||
|
|
text-align: center;
|
|||
|
|
transition: transform 0.2s;
|
|||
|
|
}
|
|||
|
|
.product-card:hover {
|
|||
|
|
transform: translateY(-5px);
|
|||
|
|
}
|
|||
|
|
.product-card img {
|
|||
|
|
width: 100%;
|
|||
|
|
border-radius: 5px;
|
|||
|
|
}
|
|||
|
|
.product-card h3 {
|
|||
|
|
font-size: 16px;
|
|||
|
|
margin: 10px 0 5px;
|
|||
|
|
}
|
|||
|
|
.product-card p {
|
|||
|
|
color: #e91e63;
|
|||
|
|
font-weight: bold;
|
|||
|
|
}
|
|||
|
|
.product-card button {
|
|||
|
|
background: #e91e63;
|
|||
|
|
border: none;
|
|||
|
|
padding: 8px 12px;
|
|||
|
|
color: #fff;
|
|||
|
|
border-radius: 3px;
|
|||
|
|
cursor: pointer;
|
|||
|
|
}
|
|||
|
|
.product-card button:hover {
|
|||
|
|
background: #c2185b;
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
</head>
|
|||
|
|
<body>
|
|||
|
|
|
|||
|
|
<!-- 顶部导航 -->
|
|||
|
|
<header>
|
|||
|
|
<h1>我的购物网站</h1>
|
|||
|
|
<nav>
|
|||
|
|
<a href="#">首页</a>
|
|||
|
|
<a href="#">分类</a>
|
|||
|
|
<a href="#">购物车</a>
|
|||
|
|
<a href="#">个人中心</a>
|
|||
|
|
</nav>
|
|||
|
|
</header>
|
|||
|
|
|
|||
|
|
<!-- banner 区域 -->
|
|||
|
|
<div class="banner"></div>
|
|||
|
|
|
|||
|
|
<!-- 商品展示区 -->
|
|||
|
|
<section class="product-list" id="productList">
|
|||
|
|
<!-- 商品卡片通过JS动态加载 -->
|
|||
|
|
</section>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
// 模拟商品数据
|
|||
|
|
const products = [
|
|||
|
|
{ id: 1, name: "高清电子书阅读器", price: 59.9, img: "https://picsum.photos/200/200?random=11" },
|
|||
|
|
{ id: 2, name: "运动健身手环", price: 199.0, img: "https://picsum.photos/200/200?random=12" },
|
|||
|
|
{ id: 3, name: "智能家居摄像头", price: 299.0, img: "https://picsum.photos/200/200?random=13" },
|
|||
|
|
{ id: 4, name: "便携式咖啡机", price: 499.0, img: "https://picsum.photos/200/200?random=14" },
|
|||
|
|
{ id: 5, name: "便携式登山背包", price: 129.0, img: "https://picsum.photos/200/200?random=15" },
|
|||
|
|
{ id: 6, name: "速干运动裤", price: 89.0, img: "https://picsum.photos/200/200?random=16" }
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
const productList = document.getElementById("productList");
|
|||
|
|
|
|||
|
|
// 渲染商品卡片
|
|||
|
|
products.forEach(product => {
|
|||
|
|
const card = document.createElement("div");
|
|||
|
|
card.className = "product-card";
|
|||
|
|
card.innerHTML = `
|
|||
|
|
<img src="${product.img}" alt="${product.name}">
|
|||
|
|
<h3>${product.name}</h3>
|
|||
|
|
<p>¥${product.price.toFixed(2)}</p>
|
|||
|
|
<button onclick="addToCart(${product.id})">加入购物车</button>
|
|||
|
|
`;
|
|||
|
|
productList.appendChild(card);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 模拟加入购物车
|
|||
|
|
function addToCart(id) {
|
|||
|
|
const product = products.find(p => p.id === id);
|
|||
|
|
alert(`已将【${product.name}】加入购物车!`);
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
</body>
|
|||
|
|
</html>
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 3. 商品详情页逻辑
|
|||
|
|
|
|||
|
|
- detail.html
|
|||
|
|
|
|||
|
|
```html
|
|||
|
|
<!DOCTYPE html>
|
|||
|
|
<html lang="zh-CN">
|
|||
|
|
<head>
|
|||
|
|
<meta charset="UTF-8">
|
|||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|||
|
|
<title>商品详情</title>
|
|||
|
|
<link rel="stylesheet" href="css/style.css">
|
|||
|
|
<style>
|
|||
|
|
.detail-container {
|
|||
|
|
max-width: 1000px;
|
|||
|
|
margin: 30px auto;
|
|||
|
|
display: flex;
|
|||
|
|
gap: 30px;
|
|||
|
|
background: #fff;
|
|||
|
|
padding: 20px;
|
|||
|
|
border-radius: 6px;
|
|||
|
|
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
|
|||
|
|
}
|
|||
|
|
.detail-container img {
|
|||
|
|
width: 400px;
|
|||
|
|
border-radius: 4px;
|
|||
|
|
}
|
|||
|
|
.detail-info {
|
|||
|
|
flex: 1;
|
|||
|
|
}
|
|||
|
|
.detail-info h2 {
|
|||
|
|
margin: 0 0 15px;
|
|||
|
|
font-size: 22px;
|
|||
|
|
}
|
|||
|
|
.detail-info p {
|
|||
|
|
margin: 8px 0;
|
|||
|
|
}
|
|||
|
|
.detail-price {
|
|||
|
|
color: #e91e63;
|
|||
|
|
font-size: 20px;
|
|||
|
|
margin: 10px 0;
|
|||
|
|
}
|
|||
|
|
.detail-actions {
|
|||
|
|
margin-top: 20px;
|
|||
|
|
}
|
|||
|
|
.detail-actions input {
|
|||
|
|
width: 60px;
|
|||
|
|
padding: 6px;
|
|||
|
|
margin-right: 10px;
|
|||
|
|
}
|
|||
|
|
.detail-actions button {
|
|||
|
|
padding: 10px 20px;
|
|||
|
|
margin-right: 10px;
|
|||
|
|
background: #333;
|
|||
|
|
color: #fff;
|
|||
|
|
border: none;
|
|||
|
|
border-radius: 4px;
|
|||
|
|
cursor: pointer;
|
|||
|
|
}
|
|||
|
|
.detail-actions button:hover {
|
|||
|
|
background: #e91e63;
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
</head>
|
|||
|
|
<body>
|
|||
|
|
|
|||
|
|
<!-- 顶部导航 -->
|
|||
|
|
<header>
|
|||
|
|
<h1>我的购物网站</h1>
|
|||
|
|
<nav>
|
|||
|
|
<a href="index.html">首页</a>
|
|||
|
|
<a href="cart.html">购物车</a>
|
|||
|
|
<a href="user-center.html">个人中心</a>
|
|||
|
|
</nav>
|
|||
|
|
</header>
|
|||
|
|
|
|||
|
|
<!-- 商品详情 -->
|
|||
|
|
<div class="detail-container">
|
|||
|
|
<img id="productImg" src="" alt="商品图片">
|
|||
|
|
<div class="detail-info">
|
|||
|
|
<h2 id="productName">商品名称</h2>
|
|||
|
|
<p id="productDesc">这里是商品描述。</p>
|
|||
|
|
<p class="detail-price" id="productPrice"></p>
|
|||
|
|
<p>
|
|||
|
|
规格:
|
|||
|
|
<select id="productSpec">
|
|||
|
|
<option value="默认">默认</option>
|
|||
|
|
<option value="大号">大号</option>
|
|||
|
|
<option value="中号">中号</option>
|
|||
|
|
<option value="小号">小号</option>
|
|||
|
|
</select>
|
|||
|
|
</p>
|
|||
|
|
<div class="detail-actions">
|
|||
|
|
<input type="number" id="productQuantity" value="1" min="1">
|
|||
|
|
<button id="addToCartBtn">加入购物车</button>
|
|||
|
|
<button id="buyNowBtn">立即购买</button>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<script src="js/common.js"></script>
|
|||
|
|
<script src="js/detail.js"></script>
|
|||
|
|
</body>
|
|||
|
|
</html>
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
- js/detail.js
|
|||
|
|
|
|||
|
|
```jsx
|
|||
|
|
/**
|
|||
|
|
* 商品详情逻辑 - detail.js
|
|||
|
|
* 负责渲染商品信息 & 加入购物车 & 立即购买
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
// 模拟商品数据(实际可从 products.json 或 URL 参数获取)
|
|||
|
|
const products = [
|
|||
|
|
{ id: 1, name: "高清电子书阅读器", desc: "屏幕清晰,眼睛不疲惫。", price: 59.9, img: "https://picsum.photos/400/400?random=21" },
|
|||
|
|
{ id: 2, name: "运动健身手环", desc: "轻便舒适,适合日常和运动。", price: 199.0, img: "https://picsum.photos/400/400?random=22" },
|
|||
|
|
{ id: 3, name: "智能家居摄像头", desc: "高清画质,自带续航。", price: 299.0, img: "https://picsum.photos/400/400?random=23" },
|
|||
|
|
{ id: 4, name: "便携式咖啡机", desc: "经典时尚,操作方便。", price: 499.0, img: "https://picsum.photos/400/400?random=24" },
|
|||
|
|
{ id: 5, name: "便携式登山背包", desc: "大容量设计,适合旅行和上学。", price: 129.0, img: "https://picsum.photos/400/400?random=25" },
|
|||
|
|
{ id: 6, name: "速干运动裤", desc: "舒适弹性,适合运动休闲。", price: 89.0, img: "https://picsum.photos/400/400?random=26" }
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
// 获取 URL 参数 (例如 detail.html?id=2)
|
|||
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|||
|
|
const productId = parseInt(urlParams.get("id")) || 1; // 默认展示第1个
|
|||
|
|
|
|||
|
|
// 找到对应商品
|
|||
|
|
const product = products.find(p => p.id === productId);
|
|||
|
|
|
|||
|
|
// DOM 元素
|
|||
|
|
const productImg = document.getElementById("productImg");
|
|||
|
|
const productName = document.getElementById("productName");
|
|||
|
|
const productDesc = document.getElementById("productDesc");
|
|||
|
|
const productPrice = document.getElementById("productPrice");
|
|||
|
|
const productSpec = document.getElementById("productSpec");
|
|||
|
|
const productQuantity = document.getElementById("productQuantity");
|
|||
|
|
const addToCartBtn = document.getElementById("addToCartBtn");
|
|||
|
|
const buyNowBtn = document.getElementById("buyNowBtn");
|
|||
|
|
|
|||
|
|
// 渲染商品
|
|||
|
|
function renderProduct() {
|
|||
|
|
if (!product) {
|
|||
|
|
document.querySelector(".detail-container").innerHTML = "<p>商品不存在</p>";
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
productImg.src = product.img;
|
|||
|
|
productName.innerText = product.name;
|
|||
|
|
productDesc.innerText = product.desc;
|
|||
|
|
productPrice.innerText = formatPrice(product.price);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 加入购物车
|
|||
|
|
addToCartBtn.addEventListener("click", () => {
|
|||
|
|
const quantity = parseInt(productQuantity.value);
|
|||
|
|
const spec = productSpec.value;
|
|||
|
|
|
|||
|
|
addToCart({ ...product, spec }, quantity);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 立即购买
|
|||
|
|
buyNowBtn.addEventListener("click", () => {
|
|||
|
|
const quantity = parseInt(productQuantity.value);
|
|||
|
|
const spec = productSpec.value;
|
|||
|
|
|
|||
|
|
// 先加入购物车,再跳转到结算
|
|||
|
|
addToCart({ ...product, spec }, quantity);
|
|||
|
|
window.location.href = "checkout.html";
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
// 初始化
|
|||
|
|
renderProduct();
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 4. 购物车逻辑
|
|||
|
|
|
|||
|
|
```html
|
|||
|
|
<!DOCTYPE html>
|
|||
|
|
<html lang="zh-CN">
|
|||
|
|
<head>
|
|||
|
|
<meta charset="UTF-8">
|
|||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|||
|
|
<title>购物车</title>
|
|||
|
|
<style>
|
|||
|
|
body {
|
|||
|
|
font-family: Arial, sans-serif;
|
|||
|
|
margin: 0;
|
|||
|
|
padding: 0;
|
|||
|
|
background-color: #f5f5f5;
|
|||
|
|
}
|
|||
|
|
header {
|
|||
|
|
background-color: #333;
|
|||
|
|
color: #fff;
|
|||
|
|
padding: 15px;
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
align-items: center;
|
|||
|
|
}
|
|||
|
|
header h1 {
|
|||
|
|
margin: 0;
|
|||
|
|
font-size: 20px;
|
|||
|
|
}
|
|||
|
|
nav a {
|
|||
|
|
color: #fff;
|
|||
|
|
margin-left: 20px;
|
|||
|
|
text-decoration: none;
|
|||
|
|
}
|
|||
|
|
nav a:hover {
|
|||
|
|
text-decoration: underline;
|
|||
|
|
}
|
|||
|
|
.cart-container {
|
|||
|
|
max-width: 1000px;
|
|||
|
|
margin: 20px auto;
|
|||
|
|
padding: 20px;
|
|||
|
|
background: #fff;
|
|||
|
|
border-radius: 5px;
|
|||
|
|
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
|
|||
|
|
}
|
|||
|
|
.cart-item {
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
padding: 10px 0;
|
|||
|
|
border-bottom: 1px solid #ddd;
|
|||
|
|
}
|
|||
|
|
.cart-item img {
|
|||
|
|
width: 80px;
|
|||
|
|
height: 80px;
|
|||
|
|
object-fit: cover;
|
|||
|
|
border-radius: 5px;
|
|||
|
|
}
|
|||
|
|
.cart-item-info {
|
|||
|
|
flex: 2;
|
|||
|
|
margin-left: 15px;
|
|||
|
|
}
|
|||
|
|
.cart-item-info h3 {
|
|||
|
|
margin: 0 0 5px;
|
|||
|
|
}
|
|||
|
|
.cart-item-price {
|
|||
|
|
flex: 1;
|
|||
|
|
text-align: center;
|
|||
|
|
color: #e91e63;
|
|||
|
|
font-weight: bold;
|
|||
|
|
}
|
|||
|
|
.cart-item-quantity {
|
|||
|
|
flex: 1;
|
|||
|
|
text-align: center;
|
|||
|
|
}
|
|||
|
|
.cart-item-quantity input {
|
|||
|
|
width: 50px;
|
|||
|
|
text-align: center;
|
|||
|
|
padding: 5px;
|
|||
|
|
}
|
|||
|
|
.cart-item-remove {
|
|||
|
|
flex: 0.5;
|
|||
|
|
text-align: center;
|
|||
|
|
}
|
|||
|
|
.cart-item-remove button {
|
|||
|
|
background: #f44336;
|
|||
|
|
color: #fff;
|
|||
|
|
border: none;
|
|||
|
|
padding: 6px 10px;
|
|||
|
|
cursor: pointer;
|
|||
|
|
border-radius: 3px;
|
|||
|
|
}
|
|||
|
|
.cart-summary {
|
|||
|
|
text-align: right;
|
|||
|
|
margin-top: 20px;
|
|||
|
|
}
|
|||
|
|
.cart-summary p {
|
|||
|
|
font-size: 18px;
|
|||
|
|
margin: 5px 0;
|
|||
|
|
}
|
|||
|
|
.checkout-btn {
|
|||
|
|
background: #e91e63;
|
|||
|
|
border: none;
|
|||
|
|
padding: 10px 20px;
|
|||
|
|
color: #fff;
|
|||
|
|
border-radius: 3px;
|
|||
|
|
cursor: pointer;
|
|||
|
|
font-size: 16px;
|
|||
|
|
}
|
|||
|
|
.checkout-btn:hover {
|
|||
|
|
background: #c2185b;
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
</head>
|
|||
|
|
<body>
|
|||
|
|
|
|||
|
|
<!-- 顶部导航 -->
|
|||
|
|
<header>
|
|||
|
|
<h1>我的购物网站</h1>
|
|||
|
|
<nav>
|
|||
|
|
<a href="index.html">首页</a>
|
|||
|
|
<a href="#">分类</a>
|
|||
|
|
<a href="cart.html">购物车</a>
|
|||
|
|
<a href="#">个人中心</a>
|
|||
|
|
</nav>
|
|||
|
|
</header>
|
|||
|
|
|
|||
|
|
<!-- 购物车主体 -->
|
|||
|
|
<div class="cart-container" id="cartContainer">
|
|||
|
|
<!-- 购物车商品通过JS渲染 -->
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="cart-summary" id="cartSummary">
|
|||
|
|
<p>总金额:¥<span id="totalPrice">0.00</span></p>
|
|||
|
|
<button class="checkout-btn" onclick="checkout()">去结算</button>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
// 模拟购物车数据(后续可与详情页 addToCart 对接)
|
|||
|
|
let cart = [
|
|||
|
|
{ id: 1, name: "夏季T恤", price: 59.9, quantity: 2, img: "https://picsum.photos/200/200?random=11" },
|
|||
|
|
{ id: 2, name: "运动鞋", price: 199.0, quantity: 1, img: "https://picsum.photos/200/200?random=12" }
|
|||
|
|
];
|
|||
|
|
|
|||
|
|
const cartContainer = document.getElementById("cartContainer");
|
|||
|
|
const totalPriceEl = document.getElementById("totalPrice");
|
|||
|
|
|
|||
|
|
// 渲染购物车
|
|||
|
|
function renderCart() {
|
|||
|
|
cartContainer.innerHTML = "";
|
|||
|
|
let total = 0;
|
|||
|
|
|
|||
|
|
cart.forEach((item, index) => {
|
|||
|
|
total += item.price * item.quantity;
|
|||
|
|
const cartItem = document.createElement("div");
|
|||
|
|
cartItem.className = "cart-item";
|
|||
|
|
cartItem.innerHTML = `
|
|||
|
|
<img src="${item.img}" alt="${item.name}">
|
|||
|
|
<div class="cart-item-info">
|
|||
|
|
<h3>${item.name}</h3>
|
|||
|
|
</div>
|
|||
|
|
<div class="cart-item-price">¥${item.price.toFixed(2)}</div>
|
|||
|
|
<div class="cart-item-quantity">
|
|||
|
|
<input type="number" min="1" value="${item.quantity}" onchange="updateQuantity(${index}, this.value)">
|
|||
|
|
</div>
|
|||
|
|
<div class="cart-item-remove">
|
|||
|
|
<button onclick="removeItem(${index})">删除</button>
|
|||
|
|
</div>
|
|||
|
|
`;
|
|||
|
|
cartContainer.appendChild(cartItem);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
totalPriceEl.innerText = total.toFixed(2);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 修改数量
|
|||
|
|
function updateQuantity(index, value) {
|
|||
|
|
cart[index].quantity = parseInt(value);
|
|||
|
|
renderCart();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 删除商品
|
|||
|
|
function removeItem(index) {
|
|||
|
|
cart.splice(index, 1);
|
|||
|
|
renderCart();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 去结算
|
|||
|
|
function checkout() {
|
|||
|
|
if (cart.length === 0) {
|
|||
|
|
alert("购物车为空,无法结算!");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
alert("跳转到结算页面(模拟)");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 初始渲染
|
|||
|
|
renderCart();
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
</body>
|
|||
|
|
</html>
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 5. 结算逻辑
|
|||
|
|
|
|||
|
|
```html
|
|||
|
|
<!DOCTYPE html>
|
|||
|
|
<html lang="zh-CN">
|
|||
|
|
<head>
|
|||
|
|
<meta charset="UTF-8">
|
|||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|||
|
|
<title>结算与支付</title>
|
|||
|
|
<style>
|
|||
|
|
body {
|
|||
|
|
font-family: Arial, sans-serif;
|
|||
|
|
margin: 0;
|
|||
|
|
padding: 0;
|
|||
|
|
background-color: #f5f5f5;
|
|||
|
|
}
|
|||
|
|
header {
|
|||
|
|
background-color: #333;
|
|||
|
|
color: #fff;
|
|||
|
|
padding: 15px;
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
align-items: center;
|
|||
|
|
}
|
|||
|
|
header h1 {
|
|||
|
|
margin: 0;
|
|||
|
|
font-size: 20px;
|
|||
|
|
}
|
|||
|
|
nav a {
|
|||
|
|
color: #fff;
|
|||
|
|
margin-left: 20px;
|
|||
|
|
text-decoration: none;
|
|||
|
|
}
|
|||
|
|
nav a:hover {
|
|||
|
|
text-decoration: underline;
|
|||
|
|
}
|
|||
|
|
.checkout-container {
|
|||
|
|
max-width: 1000px;
|
|||
|
|
margin: 20px auto;
|
|||
|
|
padding: 20px;
|
|||
|
|
background: #fff;
|
|||
|
|
border-radius: 5px;
|
|||
|
|
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
|
|||
|
|
}
|
|||
|
|
h2 {
|
|||
|
|
border-left: 4px solid #e91e63;
|
|||
|
|
padding-left: 10px;
|
|||
|
|
margin-top: 20px;
|
|||
|
|
}
|
|||
|
|
.form-group {
|
|||
|
|
margin: 15px 0;
|
|||
|
|
}
|
|||
|
|
.form-group label {
|
|||
|
|
display: block;
|
|||
|
|
margin-bottom: 5px;
|
|||
|
|
}
|
|||
|
|
.form-group input {
|
|||
|
|
width: 100%;
|
|||
|
|
padding: 8px;
|
|||
|
|
border: 1px solid #ccc;
|
|||
|
|
border-radius: 3px;
|
|||
|
|
}
|
|||
|
|
.order-summary {
|
|||
|
|
margin-top: 20px;
|
|||
|
|
padding: 15px;
|
|||
|
|
border: 1px solid #ddd;
|
|||
|
|
border-radius: 5px;
|
|||
|
|
background: #fafafa;
|
|||
|
|
}
|
|||
|
|
.order-summary p {
|
|||
|
|
margin: 8px 0;
|
|||
|
|
font-size: 16px;
|
|||
|
|
}
|
|||
|
|
.payment-options {
|
|||
|
|
margin-top: 15px;
|
|||
|
|
}
|
|||
|
|
.payment-options label {
|
|||
|
|
margin-right: 15px;
|
|||
|
|
}
|
|||
|
|
.checkout-btn {
|
|||
|
|
margin-top: 20px;
|
|||
|
|
background: #e91e63;
|
|||
|
|
border: none;
|
|||
|
|
padding: 12px 20px;
|
|||
|
|
color: #fff;
|
|||
|
|
border-radius: 3px;
|
|||
|
|
cursor: pointer;
|
|||
|
|
font-size: 16px;
|
|||
|
|
}
|
|||
|
|
.checkout-btn:hover {
|
|||
|
|
background: #c2185b;
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
</head>
|
|||
|
|
<body>
|
|||
|
|
|
|||
|
|
<!-- 顶部导航 -->
|
|||
|
|
<header>
|
|||
|
|
<h1>我的购物网站</h1>
|
|||
|
|
<nav>
|
|||
|
|
<a href="index.html">首页</a>
|
|||
|
|
<a href="#">分类</a>
|
|||
|
|
<a href="cart.html">购物车</a>
|
|||
|
|
<a href="#">个人中心</a>
|
|||
|
|
</nav>
|
|||
|
|
</header>
|
|||
|
|
|
|||
|
|
<!-- 结算主体 -->
|
|||
|
|
<div class="checkout-container">
|
|||
|
|
<h2>收货信息</h2>
|
|||
|
|
<div class="form-group">
|
|||
|
|
<label for="name">收货人姓名</label>
|
|||
|
|
<input type="text" id="name" placeholder="请输入姓名">
|
|||
|
|
</div>
|
|||
|
|
<div class="form-group">
|
|||
|
|
<label for="phone">联系电话</label>
|
|||
|
|
<input type="text" id="phone" placeholder="请输入手机号">
|
|||
|
|
</div>
|
|||
|
|
<div class="form-group">
|
|||
|
|
<label for="address">收货地址</label>
|
|||
|
|
<input type="text" id="address" placeholder="请输入详细地址">
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<h2>订单信息</h2>
|
|||
|
|
<div class="order-summary" id="orderSummary">
|
|||
|
|
<!-- 模拟订单商品信息 -->
|
|||
|
|
<p>夏季T恤 x2 — ¥119.80</p>
|
|||
|
|
<p>运动鞋 x1 — ¥199.00</p>
|
|||
|
|
<p><strong>总金额:¥318.80</strong></p>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<h2>支付方式</h2>
|
|||
|
|
<div class="payment-options">
|
|||
|
|
<label><input type="radio" name="payment" value="支付宝"> 支付宝</label>
|
|||
|
|
<label><input type="radio" name="payment" value="微信支付"> 微信支付</label>
|
|||
|
|
<label><input type="radio" name="payment" value="银行卡"> 银行卡</label>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<button class="checkout-btn" onclick="confirmOrder()">确认支付</button>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
function confirmOrder() {
|
|||
|
|
const name = document.getElementById("name").value.trim();
|
|||
|
|
const phone = document.getElementById("phone").value.trim();
|
|||
|
|
const address = document.getElementById("address").value.trim();
|
|||
|
|
const payment = document.querySelector("input[name='payment']:checked");
|
|||
|
|
|
|||
|
|
if (!name || !phone || !address) {
|
|||
|
|
alert("请填写完整的收货信息!");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
if (!payment) {
|
|||
|
|
alert("请选择支付方式!");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
alert(`订单已提交!收货人:${name}, 支付方式:${payment.value}`);
|
|||
|
|
// 这里可跳转到订单成功页
|
|||
|
|
window.location.href = "order-success.html";
|
|||
|
|
}
|
|||
|
|
</script>
|
|||
|
|
|
|||
|
|
</body>
|
|||
|
|
</html>
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 6. 订单成功页逻辑
|
|||
|
|
|
|||
|
|
```html
|
|||
|
|
<!DOCTYPE html>
|
|||
|
|
<html lang="zh-CN">
|
|||
|
|
<head>
|
|||
|
|
<meta charset="UTF-8">
|
|||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|||
|
|
<title>订单成功</title>
|
|||
|
|
<style>
|
|||
|
|
body {
|
|||
|
|
font-family: Arial, sans-serif;
|
|||
|
|
margin: 0;
|
|||
|
|
padding: 0;
|
|||
|
|
background-color: #f5f5f5;
|
|||
|
|
text-align: center;
|
|||
|
|
}
|
|||
|
|
header {
|
|||
|
|
background-color: #333;
|
|||
|
|
color: #fff;
|
|||
|
|
padding: 15px;
|
|||
|
|
}
|
|||
|
|
header h1 {
|
|||
|
|
margin: 0;
|
|||
|
|
font-size: 20px;
|
|||
|
|
}
|
|||
|
|
.success-container {
|
|||
|
|
max-width: 600px;
|
|||
|
|
margin: 50px auto;
|
|||
|
|
padding: 30px;
|
|||
|
|
background: #fff;
|
|||
|
|
border-radius: 5px;
|
|||
|
|
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
|
|||
|
|
}
|
|||
|
|
.success-icon {
|
|||
|
|
font-size: 60px;
|
|||
|
|
color: #4caf50;
|
|||
|
|
margin-bottom: 20px;
|
|||
|
|
}
|
|||
|
|
.success-container h2 {
|
|||
|
|
margin-top: 0;
|
|||
|
|
color: #333;
|
|||
|
|
}
|
|||
|
|
.success-container p {
|
|||
|
|
color: #666;
|
|||
|
|
font-size: 16px;
|
|||
|
|
margin: 10px 0 20px;
|
|||
|
|
}
|
|||
|
|
.success-actions a {
|
|||
|
|
display: inline-block;
|
|||
|
|
margin: 10px;
|
|||
|
|
padding: 12px 20px;
|
|||
|
|
border-radius: 3px;
|
|||
|
|
text-decoration: none;
|
|||
|
|
color: #fff;
|
|||
|
|
font-size: 16px;
|
|||
|
|
}
|
|||
|
|
.btn-home {
|
|||
|
|
background: #2196f3;
|
|||
|
|
}
|
|||
|
|
.btn-home:hover {
|
|||
|
|
background: #1976d2;
|
|||
|
|
}
|
|||
|
|
.btn-orders {
|
|||
|
|
background: #e91e63;
|
|||
|
|
}
|
|||
|
|
.btn-orders:hover {
|
|||
|
|
background: #c2185b;
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
</head>
|
|||
|
|
<body>
|
|||
|
|
|
|||
|
|
<!-- 顶部导航 -->
|
|||
|
|
<header>
|
|||
|
|
<h1>我的购物网站</h1>
|
|||
|
|
</header>
|
|||
|
|
|
|||
|
|
<!-- 成功提示内容 -->
|
|||
|
|
<div class="success-container">
|
|||
|
|
<div class="success-icon">✔</div>
|
|||
|
|
<h2>订单提交成功!</h2>
|
|||
|
|
<p>感谢您的购买,我们会尽快为您发货。</p>
|
|||
|
|
<div class="success-actions">
|
|||
|
|
<a href="index.html" class="btn-home">返回首页</a>
|
|||
|
|
<a href="user-center.html" class="btn-orders">查看我的订单</a>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
</body>
|
|||
|
|
</html>
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 7. 个人中心逻辑代码
|
|||
|
|
|
|||
|
|
- user-center.html
|
|||
|
|
|
|||
|
|
```html
|
|||
|
|
<!DOCTYPE html>
|
|||
|
|
<html lang="zh-CN">
|
|||
|
|
<head>
|
|||
|
|
<meta charset="UTF-8">
|
|||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|||
|
|
<title>个人中心</title>
|
|||
|
|
<link rel="stylesheet" href="css/style.css">
|
|||
|
|
<style>
|
|||
|
|
body {
|
|||
|
|
font-family: Arial, sans-serif;
|
|||
|
|
margin: 0;
|
|||
|
|
padding: 0;
|
|||
|
|
background-color: #f5f5f5;
|
|||
|
|
}
|
|||
|
|
header {
|
|||
|
|
background-color: #333;
|
|||
|
|
color: #fff;
|
|||
|
|
padding: 15px;
|
|||
|
|
display: flex;
|
|||
|
|
justify-content: space-between;
|
|||
|
|
align-items: center;
|
|||
|
|
}
|
|||
|
|
header h1 {
|
|||
|
|
margin: 0;
|
|||
|
|
font-size: 20px;
|
|||
|
|
}
|
|||
|
|
nav a {
|
|||
|
|
color: #fff;
|
|||
|
|
margin-left: 20px;
|
|||
|
|
text-decoration: none;
|
|||
|
|
}
|
|||
|
|
nav a:hover {
|
|||
|
|
text-decoration: underline;
|
|||
|
|
}
|
|||
|
|
.user-container {
|
|||
|
|
max-width: 1000px;
|
|||
|
|
margin: 20px auto;
|
|||
|
|
padding: 20px;
|
|||
|
|
background: #fff;
|
|||
|
|
border-radius: 5px;
|
|||
|
|
box-shadow: 0 2px 6px rgba(0,0,0,0.1);
|
|||
|
|
}
|
|||
|
|
h2 {
|
|||
|
|
border-left: 4px solid #e91e63;
|
|||
|
|
padding-left: 10px;
|
|||
|
|
margin-top: 20px;
|
|||
|
|
}
|
|||
|
|
.order {
|
|||
|
|
border-bottom: 1px solid #ddd;
|
|||
|
|
padding: 15px 0;
|
|||
|
|
}
|
|||
|
|
.order:last-child {
|
|||
|
|
border-bottom: none;
|
|||
|
|
}
|
|||
|
|
.order h3 {
|
|||
|
|
margin: 0 0 10px;
|
|||
|
|
}
|
|||
|
|
.order p {
|
|||
|
|
margin: 4px 0;
|
|||
|
|
color: #555;
|
|||
|
|
}
|
|||
|
|
.order-items {
|
|||
|
|
margin-top: 10px;
|
|||
|
|
padding-left: 15px;
|
|||
|
|
}
|
|||
|
|
.no-orders {
|
|||
|
|
text-align: center;
|
|||
|
|
color: #999;
|
|||
|
|
margin: 30px 0;
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
</head>
|
|||
|
|
<body>
|
|||
|
|
|
|||
|
|
<!-- 顶部导航 -->
|
|||
|
|
<header>
|
|||
|
|
<h1>我的购物网站</h1>
|
|||
|
|
<nav>
|
|||
|
|
<a href="index.html">首页</a>
|
|||
|
|
<a href="cart.html">购物车</a>
|
|||
|
|
<a href="user-center.html">个人中心</a>
|
|||
|
|
</nav>
|
|||
|
|
</header>
|
|||
|
|
|
|||
|
|
<!-- 用户中心主体 -->
|
|||
|
|
<div class="user-container">
|
|||
|
|
<h2>我的订单</h2>
|
|||
|
|
<div id="orderList"></div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<script src="js/common.js"></script>
|
|||
|
|
<script src="js/user-center.js"></script>
|
|||
|
|
</body>
|
|||
|
|
</html>
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
- js/user-center.js
|
|||
|
|
|
|||
|
|
```jsx
|
|||
|
|
/**
|
|||
|
|
* 个人中心逻辑 - user-center.js
|
|||
|
|
* 负责渲染用户的历史订单
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
const orderListEl = document.getElementById("orderList");
|
|||
|
|
|
|||
|
|
function renderOrders() {
|
|||
|
|
const orders = getOrders(); // 调用 common.js 获取订单数据
|
|||
|
|
|
|||
|
|
if (orders.length === 0) {
|
|||
|
|
orderListEl.innerHTML = `<p class="no-orders">暂无订单记录</p>`;
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
orders.forEach(order => {
|
|||
|
|
const orderDiv = document.createElement("div");
|
|||
|
|
orderDiv.className = "order";
|
|||
|
|
orderDiv.innerHTML = `
|
|||
|
|
<h3>订单号:${order.id}</h3>
|
|||
|
|
<p>收货人:${order.user} | 电话:${order.phone}</p>
|
|||
|
|
<p>收货地址:${order.address}</p>
|
|||
|
|
<p>支付方式:${order.payment}</p>
|
|||
|
|
<p>下单时间:${order.createdAt}</p>
|
|||
|
|
<p><strong>总金额:${formatPrice(order.total)}</strong></p>
|
|||
|
|
<div class="order-items">
|
|||
|
|
${order.items.map(item => `
|
|||
|
|
<p>${item.name}${item.spec ? " - " + item.spec : ""} x${item.quantity} — ${formatPrice(item.price * item.quantity)}</p>
|
|||
|
|
`).join("")}
|
|||
|
|
</div>
|
|||
|
|
`;
|
|||
|
|
orderListEl.appendChild(orderDiv);
|
|||
|
|
});
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 初始化
|
|||
|
|
renderOrders();
|
|||
|
|
```
|