资讯动态

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

发布时间:2026/10/18 21:21:11 来源:尧图企业网站定制
简介这是一套面向前端初学者与进阶学习者的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 里没有 usersgetItem 返回 nullnull || []会得到[]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 classgoods-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。希望这个习惯也能帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑