news 2026/10/18 21:21:01

HTML5静态购物网站带登录注册与购物车完整实现教程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HTML5静态购物网站带登录注册与购物车完整实现教程

简介:这是一套面向前端初学者与进阶学习者的HTML5静态购物网站完整源码,围绕登录注册、商品展示、详情页与购物车等核心模块展开,帮助读者理解如何用HTML5、CSS3、JavaScript与jQuery搭建一个可运行的电商前端原型。压缩包共48个文件,约5.28MB,其中4个html页面承载首页、登录、详情与购物车结构,5个css文件负责响应式布局与视觉美化,8个js文件实现轮播、三级菜单、购物车增删改查等交互逻辑,另有16个png与14个jpg图片资源及1个json配置文件,覆盖页面素材与开发环境设置。目前已有1041人学习下载。资源目录按页面、样式、脚本与图片分层组织,便于对照理解登录状态保持、轮播切换、三级导航展开及购物车金额实时计算等实现思路,适合作为课程设计、毕业设计或前端练习的参考案例。

1. 从一份能直接跑起来的静态购物站说起

前阵子帮一个刚入行的朋友看简历项目,他丢过来一个压缩包,说“哥你帮我看看这个能不能写进简历”。解压之后我愣了一下——一个完整的购物网站,首页、商品列表、详情页、购物车、登录注册全都有,但整个项目里没有一行后端代码,没有数据库,没有 npm install,双击 index.html 就能在浏览器里跑起来。这就是典型的 html5 购物网站带登录 的静态实现:用 html 搭骨架,css 做视觉,jQuery 处理交互,localStorage 存登录态和购物车数据。

这类项目特别适合两类人:一是刚学完 html、css、js 想找个完整项目练手的同学,二是需要快速交付一个纯前端演示站、给客户看交互效果的开发者。它不依赖任何服务器环境,丢到任何静态托管上都能访问,改起来也直观——想换配色改 css,想加商品改一个 js 数组,想调交互逻辑就在 jQuery 事件里动手。下面我就按“这项目怎么组织的、怎么跑起来、核心代码长什么样、怎么改成自己的”这条线,把它拆开讲一遍。

2. 项目结构与技术选型:为什么用 jQuery 而不是框架

2.1 目录组织与文件职责

拿到这个项目,第一件事是看目录。静态购物站的目录结构通常长这样,我按实际拆包经验还原一份典型的:

shop-static/ ├── index.html # 首页,商品推荐 + 轮播 ├── list.html # 商品列表页,支持分类筛选 ├── detail.html # 商品详情页,加购入口 ├── cart.html # 购物车页,数量增减、结算 ├── login.html # 登录 / 注册页 ├── css/ │ ├── reset.css # 浏览器默认样式重置 │ ├── common.css # 公共样式:头部、底部、按钮 │ └── pages.css # 各页面专属样式 ├── js/ │ ├── jquery.min.js # jQuery 库文件 │ ├── data.js # 商品数据(模拟后端返回) │ ├── common.js # 公共逻辑:登录态、购物车读写 │ └── pages.js # 各页面交互逻辑 ├── images/ # 商品图、图标、banner └── lib/ # 可能放 swiper 等轮播插件

这个分法的核心思路是“数据、公共逻辑、页面逻辑”三层分离。data.js 只负责吐数据,common.js 管登录态和购物车这种跨页面共享的状态,pages.js 按页面路径判断当前在哪个页面、绑定对应事件。新手最容易犯的错是把所有 js 塞进一个文件,改到后面自己都找不到哪段代码管哪个按钮。

2.2 技术选型:jQuery 在这个场景下为什么还成立

很多人一看 jQuery 就皱眉,觉得 2024 年了还用这玩意儿。但放到“静态购物站 + 新手练手 + 快速演示”这个具体场景里,jQuery 反而有它的道理。第一,它不需要构建工具,一个 script 标签引入就能用,省掉了 webpack、vite 那一整套配置,对刚学完基础语法的人友好。第二,DOM 操作和事件绑定是它的强项,购物站里大量的“点击加购”“数量增减”“切换分类”本质就是 DOM 操作,jQuery 的$('.btn').on('click', fn)比原生addEventListener写起来短。第三,ajax 请求封装得简单,后面想接真实后端,$.ajax或$.get改起来成本低。

当然,如果这个项目要往大了做,比如商品上千、需要组件复用、要上路由,那确实该换 Vue 或 React。但作为一份“能跑起来、能看懂、能改”的静态站,jQuery 的性价比是成立的。我一般会跟朋友说:先把这个跑通,理解购物车的状态怎么流转,再去上框架,你会知道框架帮你解决了什么问题。

2.3 数据层设计:用 js 数组模拟后端接口

静态站没有数据库,商品数据只能写在前端。常见做法是在 data.js 里定义一个全局数组,每个对象代表一个商品:

// js/data.js // 模拟后端返回的商品列表,字段命名尽量贴近真实接口 var goodsList = [ { id: 1001, // 商品唯一标识,加购和详情页靠它定位 name: '纯棉短袖T恤', // 商品名 price: 89.00, // 单价,用数字方便计算 img: 'images/goods/1001.jpg',// 主图路径 category: 'clothing', // 分类标识,列表页筛选用 stock: 50, // 库存,加购时校验 desc: '夏季新款,透气舒适' // 详情页描述 }, { id: 1002, name: '帆布休闲鞋', price: 199.00, img: 'images/goods/1002.jpg', category: 'shoes', stock: 30, desc: '百搭款,适合日常通勤' } // ... 更多商品 ];

这里有几个细节值得说。id 用数字而不是字符串,是为了后面购物车合并同款商品时方便比较;price 存数字不存'89.00'这种字符串,因为结算时要累加,字符串相加会变成拼接;category 用英文标识而不是中文,是为了筛选时做等值判断不受编码影响。这些看着小,但都是实际写的时候容易翻车的地方。数据层定好了,后面所有页面都从这个数组里取数据,改商品只需要改这一个文件。

3. 登录态与购物车:两个核心状态的读写实现

3.1 登录注册:localStorage 存 token 的完整流程

静态站没有真正的后端鉴权,登录逻辑本质是“把用户信息存到本地,其他页面读出来判断是否登录”。注册和登录都走 localStorage。先看注册:

// js/common.js // 注册:把用户信息存进 localStorage 的 users 列表 function register(username, password) { // 取出已有用户,没有就初始化空数组 var users = JSON.parse(localStorage.getItem('users') || '[]'); // 检查用户名是否已存在,避免重复注册 var exist = users.some(function (u) { return u.username === username; }); if (exist) { return { code: 1, msg: '用户名已存在' }; } // 实际项目里密码不能明文存,这里演示用简单处理 users.push({ username: username, password: password }); localStorage.setItem('users', JSON.stringify(users)); return { code: 0, msg: '注册成功' }; }

注册的核心是把用户数组序列化后写回 localStorage。JSON.parse(localStorage.getItem('users') || '[]')这个写法很关键——第一次访问时 localStorage 里没有 users,getItem 返回 null,null || '[]'会得到'[]',parse 出来就是空数组,避免了 null 报错。这是静态站里处理“首次访问”的通用套路。

登录则是校验后写入当前登录态:

// 登录:校验账号密码,成功后写入 currentUser function login(username, password) { var users = JSON.parse(localStorage.getItem('users') || '[]'); var target = users.find(function (u) { return u.username === username && u.password === password; }); if (!target) { return { code: 1, msg: '账号或密码错误' }; } // 写入当前登录用户,其他页面靠这个判断登录态 localStorage.setItem('currentUser', JSON.stringify({ username: target.username, loginTime: Date.now() })); return { code: 0, msg: '登录成功' }; }

登录成功后写的是currentUser而不是直接改 users,这样退出登录只需要removeItem('currentUser'),不会影响注册数据。判断是否登录就一行:var isLogin = !!localStorage.getItem('currentUser')。页面加载时调这个判断,没登录就跳 login.html,登录了就渲染用户名。

3.2 购物车:增删改查与同款合并

购物车是静态站里逻辑最密的部分。数据结构一般是一个数组,每项包含商品 id、数量、加购时的单价快照:

// 加入购物车:同款商品数量累加,新款则追加 function addToCart(goodsId, count) { count = count || 1; var cart = JSON.parse(localStorage.getItem('cart') || '[]'); // 找到同款商品 var item = cart.find(function (g) { return g.id === goodsId; }); if (item) { item.count += count; // 已存在则累加数量 } else { // 从商品数据里查出完整信息,存一份价格快照 var goods = goodsList.find(function (g) { return g.id === goodsId; }); if (!goods) return { code: 1, msg: '商品不存在' }; cart.push({ id: goods.id, name: goods.name, price: goods.price, // 价格快照,防止后续改价影响已加购订单 img: goods.img, count: count }); } localStorage.setItem('cart', JSON.stringify(cart)); return { code: 0, msg: '已加入购物车' }; }

这里有个设计点:加购时把 price 存了一份快照,而不是每次渲染时去 goodsList 里现查。原因是商品价格可能被改,如果购物车里存的是引用,改价后购物车金额会跟着变,用户会觉得“我加购时不是这个价”。存快照是电商里的常规做法,静态站虽然简单,但这个意识要有。

数量增减和删除就是对这个数组做修改:

// 修改购物车某商品数量,count 为 0 时删除 function updateCartCount(goodsId, count) { var cart = JSON.parse(localStorage.getItem('cart') || '[]'); if (count <= 0) { // 数量减到 0 直接移除 cart = cart.filter(function (g) { return g.id !== goodsId; }); } else { var item = cart.find(function (g) { return g.id === goodsId; }); if (item) item.count = count; } localStorage.setItem('cart', JSON.stringify(cart)); return cart; }

filter用来删除,find用来定位,这两个数组方法在购物车逻辑里出现频率极高。渲染购物车时遍历数组,每项算price * count,最后 reduce 出总价。整个购物车不依赖任何后端,刷新页面数据还在,这就是 localStorage 的价值。

3.3 页面渲染:数据怎么变成 DOM

数据有了,得渲染到页面上。以商品列表页为例,常见做法是拼字符串再塞进容器:

// js/pages.js // 渲染商品列表,category 为空则显示全部 function renderGoodsList(category) { var list = goodsList; if (category) { // 按分类筛选 list = goodsList.filter(function (g) { return g.category === category; }); } var html = ''; list.forEach(function (g) { // 用模板字符串拼卡片,data-id 挂商品 id 供点击时读取 html += '<div class="goods-card">// 事件委托:绑在容器上,动态生成的按钮也能响应 $('#goodsContainer').on('click', '.add-cart', function () { var id = $(this).closest('.goods-card').data('id'); var res = addToCart(id, 1); if (res.code === 0) { alert('已加入购物车'); updateCartBadge(); // 更新头部购物车角标 } });

委托绑定的原理是事件冒泡:点击按钮冒泡到容器,容器再根据选择器匹配。这样无论商品卡片怎么重新渲染,事件都不会丢。新手常犯的错是把 click 直接绑在.add-cart上,第一次渲染能用,筛选后重新渲染就失效了,然后到处找原因——这就是典型的踩坑点。

4. 避坑与常见问题:静态站里那些容易翻车的地方

4.1 刷新后登录态丢失或误判

现象:登录后跳转到首页,刷新一下又变成未登录,或者明明没登录却显示用户名。原因通常是登录态判断写在了页面加载之后,或者判断逻辑用了localStorage.getItem('currentUser')直接当布尔值——它返回的是字符串'null'时也是真值。解决:统一封装isLogin()函数,用!!localStorage.getItem('currentUser')判断,并在每个页面<head>里尽早执行跳转逻辑,别等 DOM 加载完。

4.2 购物车数量显示不同步

现象:加了商品,头部角标还是 0,刷新才对。原因是角标只在页面加载时算了一次,加购后没重新计算。解决:把角标更新抽成独立函数updateCartBadge(),每次购物车数据变动后都调一次。这个函数遍历 cart 数组累加 count,写到角标元素里。养成“数据变、视图跟着变”的习惯,后面上框架会顺很多。

4.3 商品 id 类型不一致导致合并失败

现象:同一件商品加购两次,购物车里出现两条而不是数量变 2。原因是第一次加购时 id 从 DOM 的>/* css/common.css */ :root { --primary: #ff5000; /* 主色,按钮、价格、高亮 */ --bg: #f5f5f5; /* 页面背景 */ --text: #333; /* 主文字 */ --radius: 8px; /* 圆角统一 */ } .btn-primary { background: var(--primary); border-radius: var(--radius); }

改配色只动--primary一个值,全站按钮、价格、角标跟着变。这是把静态站做成“可换肤”的最低成本方案。如果项目里还没用变量,改造时顺手抽出来,后面维护省事。

5.3 接后端:把 localStorage 换成接口调用

静态站要变成真项目,核心是把 common.js 里的读写换成 ajax。改造思路是保持函数签名不变,只换内部实现:

// 改造前:从 localStorage 读购物车 function getCart() { return JSON.parse(localStorage.getItem('cart') || '[]'); } // 改造后:从后端接口读,返回 Promise function getCart() { return $.get('/api/cart').then(function (res) { return res.data; // 约定后端返回 { code, data, msg } }); }

调用处从var cart = getCart()改成getCart().then(function(cart){ ... })。登录同理,把 login 函数里的 localStorage 写入换成$.post('/api/login', {...}),成功后把后端返回的 token 存起来,后续请求带上。改造时建议一个模块一个模块来,先改登录,跑通再改购物车,别一次性全换,否则出问题不知道是哪块的。

5.4 一个我踩过的坑:别在渲染函数里读 localStorage

早期我写这类项目,喜欢在渲染函数里直接JSON.parse(localStorage.getItem('cart')),图省事。结果页面一多,同一个数据在五六个地方各读各的,改了一处忘了另一处,购物车金额和角标对不上,排查了半天。后来我强制自己:所有 localStorage 读写只允许出现在 common.js 的数据层函数里,页面逻辑一律调函数,不直接碰 localStorage。这个习惯让我后面接后端时几乎没改页面代码,只换了数据层实现。从那以后我每次开新项目,第一件事就是把数据读写收口到一个文件,哪怕它只是个静态 demo。希望这个习惯也能帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/18 21:11:15

Dify本地部署Chrome MCP实战:3分钟搭建网页自动化AI助手

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/18 21:10:45

MATLAB复现HANK模型:从离散化到脉冲响应的完整链路

简介&#xff1a;这份资源面向宏观经济学研究者、高年级研究生及具备一定MATLAB基础的量化分析人员&#xff0c;提供异构代理新凯恩斯&#xff08;HANK&#xff09;模型的完整复制代码&#xff0c;用于在MATLAB环境中搭建、求解并模拟包含家庭与企业异质性的动态随机一般均衡框…

作者头像 李华
网站建设 2026/10/18 21:10:38

深度特征映射语音增强实战:从STFT特征到全连接网络训练全解析

简介&#xff1a;一套基于深度特征映射的语音增强工程实现&#xff0c;面向计算机专业学生与开发者&#xff0c;可支撑毕业设计、课程实训及公司项目二次开发。整套资源共一百四十四个文件&#xff0c;约五十七点八一兆字节&#xff0c;核心包含四十三个Python脚本、三十八个TX…

作者头像 李华
网站建设 2026/10/18 21:07:05

VS Code 接入 MCP 服务:打造 AI 数据工作站完整指南

我个人一直觉得&#xff0c;VS Code 是个越用越“重”的编辑器&#xff0c;但这个“重”不是贬义——它意味着你可以把一大堆工具塞进去&#xff0c;让所有开发动作都在同一个窗口里完成。最近我把它正式改造成了 AI 工作站&#xff0c;核心就是接入了 Ace Data Cloud 的 MCP 服…

作者头像 李华
网站建设 2026/10/18 21:05:00

wxWidgets 3.2.8 与 Code::Blocks 25.03 配置实战:从编译到运行避坑指南

简介&#xff1a;这份资源是已预先配置好 wxWidgets 3.2.8 的 CodeBlocks 25.03 集成开发环境&#xff0c;面向希望快速上手 C 跨平台 GUI 开发的新手与有经验的开发者&#xff0c;省去手动编译配置 wxWidgets 库的繁琐过程。压缩包为 7z 格式&#xff0c;整体约 600.98MB&…

作者头像 李华