Bootstrap手机商城源码实战:从跑起来到接口驱动改造
发布时间:2026/10/18 15:45:17 锦皓数字建站

简介这是一套基于Bootstrap框架搭建的手机商城前端模板面向具备一定HTML、CSS与JavaScript基础、希望快速构建移动端购物平台的开发者。项目采用响应式布局与12列栅格系统整合导航栏、轮播图、模态框等预定义组件及JavaScript插件并预留后端接口调用能力便于对接RESTful API实现数据动态交互。压缩包共69个文件包含45个html页面、10张jpg图片、5个js脚本、2个css样式表及png、svg、字体等资源整体约434KB涵盖商品展示、购物车、用户登录注册、订单处理、个人中心、钱包与优惠券等常见模块页面。目前已有947人学习下载适合作为课程设计、毕业设计或移动电商原型的参考模板帮助读者快速理解Bootstrap组件组织方式与商城页面结构节省从零搭建界面的时间。1. 从一份“能跑起来”的 Bootstrap 手机商城源码说起很多前端新手卡在“学完 Bootstrap 栅格和组件却拼不出一个完整页面”这一步。这份基于 Bootstrap 设计的手机商城源码正好补上这个缺口它不是零散 demo而是一个带首页轮播、商品列表、详情页、购物车和结算入口的完整静态站点。技术栈就是 Bootstrap 4/5 原生 JavaScript 少量 jQuery 插件没有构建工具双击index.html就能看效果。适合谁适合刚学完 HTML/CSS、想拿一个真实电商页面练手的前端新人也适合需要快速搭后台管理页面的全栈开发者——把商品数据换成接口返回它就是一个能用的商城前端骨架。下面我按“能干什么 → 怎么跑 → 怎么改”的顺序把这份源码拆开讲。2. 项目结构与技术选型为什么用 Bootstrap 而不是手写 Flex2.1 目录结构一览拿到源码后先别急着改代码花两分钟把目录看一遍后面找文件能省一半时间。这份手机商城的目录是典型的静态站点组织方式没有src、没有dist所有资源平铺在根目录下phone-mall/ ├── index.html # 首页轮播 分类入口 商品推荐 ├── list.html # 商品列表页带筛选和排序 ├── detail.html # 商品详情页主图 规格 加入购物车 ├── cart.html # 购物车页数量增减 合计 ├── checkout.html # 结算页收货信息 订单摘要 ├── css/ │ ├── bootstrap.min.css # Bootstrap 框架样式 │ └── style.css # 项目自定义覆盖样式 ├── js/ │ ├── jquery.min.js # jQueryBootstrap 部分组件依赖 │ ├── bootstrap.bundle.min.js │ └── main.js # 项目交互逻辑轮播、购物车、表单校验 ├── images/ # 商品图、图标、占位图 └── fonts/ # 图标字体部分版本用 Font Awesome这个结构的好处是“所见即所得”改哪个页面就打开哪个 HTML不用等编译。坏处也明显——公共部分导航栏、页脚在每个 HTML 里重复了一遍改一处要改五个文件。常见做法是后期用 JavaScript 的fetch把公共片段抽成header.html、footer.html再注入或者直接上构建工具。但作为学习项目重复反而降低了理解门槛。2.2 技术选型Bootstrap 在这个场景里赢在哪手机商城这类页面有三个硬需求响应式、组件多、开发快。Bootstrap 的栅格系统.container→.row→.col-*天然解决第一点card、carousel、modal、navbar这些组件直接覆盖第二点第三点靠 CDN 或本地引入即可不需要配 webpack。具体到代码首页的商品推荐区就是标准栅格!-- 商品推荐区大屏一行4个中屏2个小屏1个 -- div classcontainer mt-4 div classrow div classcol-12 col-sm-6 col-lg-3 mb-4 div classcard h-100 shadow-sm img srcimages/phone-01.jpg classcard-img-top alt商品图 div classcard-body d-flex flex-column h5 classcard-title全面屏智能手机/h5 p classcard-text text-danger font-weight-bold¥1999/p a hrefdetail.html classbtn btn-primary mt-auto查看详情/a /div /div /div !-- 其余商品重复此结构 -- /div /divcol-12 col-sm-6 col-lg-3是核心手机竖屏占满 12 列平板占 6 列一行两个桌面占 3 列一行四个。h-100让卡片等高mt-auto把按钮压到底部避免不同商品标题长度导致按钮错位。这两个类是我在电商页面里用得最多的组合比手写 Flex 省事得多。2.3 交互逻辑放在哪main.js 的职责边界Bootstrap 负责样式和基础组件行为轮播自动播放、模态框开关但购物车加减、价格合计、表单校验这些业务逻辑得自己写。源码里统一放在js/main.js按页面用id或class做存在性判断避免在首页执行购物车代码报错// main.js 片段购物车数量增减与合计 document.addEventListener(DOMContentLoaded, function () { const cartItems document.querySelectorAll(.cart-item); if (!cartItems.length) return; // 非购物车页直接跳过 function updateTotal() { let total 0; document.querySelectorAll(.cart-item).forEach(item { const price parseFloat(item.dataset.price); const qty parseInt(item.querySelector(.qty-input).value, 10); total price * qty; item.querySelector(.item-subtotal).textContent (price * qty).toFixed(2); }); document.getElementById(cart-total).textContent total.toFixed(2); } // 事件委托加号、减号、手动输入都走这里 document.querySelector(.cart-list).addEventListener(click, function (e) { const btn e.target.closest(.btn-qty); if (!btn) return; const input btn.parentElement.querySelector(.qty-input); let qty parseInt(input.value, 10); qty btn.classList.contains(btn-plus) ? qty 1 : Math.max(1, qty - 1); input.value qty; updateTotal(); }); });这段代码有两个细节值得注意一是DOMContentLoaded里先判断.cart-item是否存在保证脚本在非购物车页不报错二是用事件委托绑定在.cart-list上而不是给每个按钮单独绑事件——商品数量动态增减时不用重新绑定。># 方式一Python 3大多数系统自带 cd phone-mall python -m http.server 8080 # 浏览器访问 http://localhost:8080 # 方式二Node.js 的 http-server需先 npm i -g http-server http-server -p 8080 # 方式三VS Code 装 Live Server 插件 # 右键 index.html → Open with Live Server用本地服务器后路径问题基本消失fetch也能正常工作。我一般用 Python 那条命令不用装任何东西改完代码刷新浏览器就行。注意端口别和已有服务冲突8080 被占用就换 8081。3.3 依赖引入方式CDN 还是本地源码里 Bootstrap 和 jQuery 可能通过 CDN 引入也可能放在js/、css/目录下。如果是 CDN断网或 CDN 被墙时页面会失去样式。检查index.html的head和/body前!-- CDN 方式检查 href/src 是否指向外部域名 -- link relstylesheet hrefhttps://cdn.jsdelivr.net/npm/bootstrap5.3.0/dist/css/bootstrap.min.css script srchttps://cdn.jsdelivr.net/npm/bootstrap5.3.0/dist/js/bootstrap.bundle.min.js/script !-- 本地方式确认文件真实存在于对应目录 -- link relstylesheet hrefcss/bootstrap.min.css script srcjs/bootstrap.bundle.min.js/script如果想让项目完全离线可用把 CDN 文件下载到本地对应目录再把href/src改成相对路径。这一步做完整个项目拷到 U 盘里也能跑。提示Bootstrap 5 已经不再依赖 jQuery但很多老教程和源码仍用 Bootstrap 4 jQuery。先看bootstrap.min.css的版本号再决定要不要引入 jQuery别盲目加。4. 核心页面拆解轮播、列表渲染与购物车状态4.1 首页轮播carousel 组件的正确用法首页顶部轮播是电商标配Bootstrap 的carousel组件开箱即用但有几个参数不设好会翻车div idmainCarousel classcarousel slide>// 商品数据实际项目中替换为接口返回 const products [ { id: 1, name: 全面屏智能手机, price: 1999, img: images/phone-01.jpg }, { id: 2, name: 轻薄拍照手机, price: 2499, img: images/phone-02.jpg }, { id: 3, name: 长续航商务机, price: 1599, img: images/phone-03.jpg } ]; // 渲染到列表容器 const listEl document.getElementById(product-list); if (listEl) { listEl.innerHTML products.map(p div classcol-12 col-sm-6 col-lg-3 mb-4 div classcard h-100 shadow-sm img src${p.img} classcard-img-top alt${p.name} div classcard-body d-flex flex-column h5 classcard-title${p.name}/h5 p classcard-text text-danger font-weight-bold¥${p.price}/p a hrefdetail.html?id${p.id} classbtn btn-primary mt-auto查看详情/a /div /div /div ).join(); }这样改的好处新增商品只改数组不用复制 HTML详情页可以通过 URL 参数?id1拿到商品 ID再用URLSearchParams读取并渲染对应数据。注意innerHTML拼接时商品名如果来自用户输入要做转义静态数据可以忽略。4.3 购物车状态localStorage 做持久化购物车数据如果只存在内存里刷新页面就没了。源码里可能用localStorage存了一个数组结构大致是[{id, name, price, qty}]。核心操作有三个加入购物车、修改数量、删除商品。// 加入购物车读取现有数据存在则数量1不存在则新增 function addToCart(product) { const cart JSON.parse(localStorage.getItem(cart) || []); const existing cart.find(item item.id product.id); if (existing) { existing.qty 1; } else { cart.push({ ...product, qty: 1 }); } localStorage.setItem(cart, JSON.stringify(cart)); updateCartBadge(); // 更新导航栏购物车角标 } // 更新角标所有页面导航栏都能看到当前商品总数 function updateCartBadge() { const cart JSON.parse(localStorage.getItem(cart) || []); const count cart.reduce((sum, item) sum item.qty, 0); document.querySelectorAll(.cart-badge).forEach(el { el.textContent count; el.style.display count 0 ? inline-block : none; }); }localStorage存的是字符串所以每次读写都要JSON.parse和JSON.stringify。角标更新函数要在每个页面加载时调用一次这样从详情页加购后跳回首页导航栏数字也是对的。注意localStorage按域名隔离用file://打开时不同 HTML 文件可能共享也可能不共享取决于浏览器实现——用本地服务器最稳。5. 避坑与排查五个我踩过的真实问题5.1 轮播图不自动播放现象页面加载后轮播图停在第一张左右箭头能点但不自动切换。原因Bootstrap 5 用>const cartApi { async add(productId, qty 1) { const res await fetch(/api/cart, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ productId, qty }) }); if (!res.ok) throw new Error(加入购物车失败); return res.json(); }, async update(itemId, qty) { return fetch(/api/cart/${itemId}, { method: PATCH, headers: { Content-Type: application/json }, body: JSON.stringify({ qty }) }); } };这样页面里只调cartApi.add(id)不关心底层是localStorage还是 HTTP。后期换后端、加 loading 状态、做错误重试都只改这一个对象。第三步公共片段组件化。导航栏和页脚在每个 HTML 里重复改起来痛苦。我的做法是在每个页面留一个div idapp-header/div用 JS 注入// 注入公共头部避免每个页面重复写导航栏 fetch(partials/header.html) .then(res res.text()) .then(html { document.getElementById(app-header).innerHTML html; updateCartBadge(); // 头部注入后再更新角标 });注意注入是异步的updateCartBadge必须放在.then里面否则 DOM 还没生成就去找.cart-badge会拿到null。这个顺序问题我翻过一次车页面角标死活不显示查了半小时才发现是异步时序。验证方法改完后用浏览器无痕模式打开确保没有旧localStorage干扰F12 切到 Network 面板看接口请求是否按预期发出、返回结构是否和渲染逻辑匹配再用手机模拟器切几个常见分辨率375、414、768确认栅格没崩。从那以后我每次改完页面都强制走一遍“无痕 Network 手机模拟”三件套比肉眼扫一遍靠谱得多。希望这份拆解能帮你把这份 Bootstrap 手机商城真正跑起来、改下去。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。