ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

1号店电商前端JS代码解析:原生JavaScript购物车与商品列表实战

1号店电商前端JS代码解析:原生JavaScript购物车与商品列表实战 简介这份资源是一套基于JavaScript的电商网站前端实现代码模拟“1号店”与京东合作场景下的核心交互功能适合前端初学者或电商项目开发者参考学习。完整包内共347个文件包含7个JS脚本、6个CSS样式、6个HTML页面及大量图片素材其中图片以jpg、png、gif为主构成商品展示、轮播动效与界面装饰所需的视觉资源代码覆盖购物车增删、用户注册验证、密码修改等典型电商模块可帮助理解DOM操作、事件监听、异步请求及表单校验的实际应用。资源包大小约3.04MB目录按页面拆分为首页、分类列表、商品详情、注册页等独立模块还附带IDE工作区配置便于直接导入工程查看。所有页面均配有对应样式与脚本整体结构清晰易读。目前已有3423人学习下载适合想通过完整项目源码快速上手电商前端开发、深入学习原生JS交互逻辑的读者。1. 1号店完整代码一套能直接跑起来的电商前端 JS 项目做电商前端的人手里肯定都存过几份「经典老代码」。这套 1号店完整代码就是从京东1号店早期页面里整理出来的前端项目包里面的 JS 代码完整覆盖了商品列表、购物车、结算页、用户中心这些电商标配模块。它最实用的地方在于不依赖 Vue、React 这类框架纯原生 HTML CSS JavaScript打开就能看改一改就能用。我建议两类人重点关注刚入行想搞懂电商页面数据流的新手以及做活动页、H5 商城时想快速抄作业的老手。这份资源能帮你把「JS 代码如何驱动一个完整的电商页面」这件事彻底看明白。2. 解开代码结构从 HTML 入口到 JS 模块的调用关系拿到代码包第一步不是双击 index.html而是先把目录结构摸清楚。老式电商前端项目的组织方式大同小异一个入口页面多个 JS 文件通过 script 标签按顺序引入外层挂公共样式图片和字体单独放目录。搞懂这套组织方式后面所有排查工作都顺了。2.1 目录结构与入口文件的加载顺序拆开压缩包后你会看到类似下面的目录结构yihaodian/ ├── css/ │ ├── base.css │ ├── index.css │ └── cart.css ├── js/ │ ├── common.js │ ├── goods.js │ ├── cart.js │ └── user.js ├── images/ ├── index.html └── cart.html先别急着改任何文件打开 index.html 看 head 里的 link 标签和底部 body 结束前的 script 标签。加载顺序是严格按照「样式先加载脚本按依赖后加载」的方式写的。以 common.js 为例它里面定义了全局的window.YHD命名空间后续所有模块都挂在这个对象下面所以它必须放在最前面!-- 正确顺序 -- link relstylesheet hrefcss/base.css link relstylesheet hrefcss/index.css ... script srcjs/common.js/script script srcjs/goods.js/script script srcjs/cart.js/script这里有个关键逻辑goods.js里的函数会调用common.js里定义的YHD.formatPrice()如果顺序反了浏览器执行到goods.js时会直接抛YHD is not defined整个页面的脚本都会中断。所以你在调整目录结构时script 标签的顺序必须保持依赖在前、被依赖在后。如果你用的是 VS Code可以直接装一个 Live Server 插件来跑这套代码。右击 index.html 选择 Open with Live Server它会在本地起一个 5500 端口的 HTTP 服务这样页面里的相对路径资源都能正常加载。2.2 JS 模块划分商品、购物车、订单、用户四大域这套代码把功能拆得很清楚每个 JS 文件只负责一类职责。虽然没有什么模块化规范但这种朴素的文件划分方式反而更容易读懂业务边界。文件职责暴露的顶层方法common.js公共工具价格格式化、URL 参数解析、消息弹层YHD.formatPriceYHD.getQuerygoods.js商品列表渲染、筛选、排序YHD.Goods.renderYHD.Goods.filtercart.js购物车加减、删除、总价计算YHD.Cart.addYHD.Cart.updateTotaluser.js登录状态展示、用户信息回填YHD.User.init这种划分方式有一个很明显的优点你改购物车逻辑时不会误碰商品渲染的代码。实际开发时我也习惯按业务域拆文件比按技术类型拆把所有的 utils 堆一个文件后期维护省心得多。3. 核心功能拆解商品列表与购物车逻辑实战想真正把这份代码吃透要盯住两条线一条是「数据怎么变成页面上的元素」另一条是「用户操作怎么反向改数据」。商品列表和购物车恰好把这两条线完整走了一遍代码量不大但五脏俱全。3.1 商品列表渲染从静态数据到 DOM 的链路商品列表的渲染逻辑集中在 goods.js。它先定义了一个数组每个商品对象包含id、name、price、img、category这些字段然后通过循环拼接字符串的方式生成 HTML一次性写入容器节点。// goods.js var productList [ { id: 1001, name: 伊利纯牛奶 250ml*12盒, price: 45.9, category: 食品, stock: 200 }, { id: 1002, name: 维达抽纸 3层100抽*24包, price: 49.9, category: 个护, stock: 150 }, { id: 1003, name: 农夫山泉 550ml*24瓶, price: 36.8, category: 食品, stock: 80 } ]; function renderGoods(filterCategory) { var container document.getElementById(goods-list); var html ; var list productList; if (filterCategory) { list productList.filter(function(item) { return item.category filterCategory; }); } for (var i 0; i list.length; i) { html div classgoods-item>// cart.js var cartData JSON.parse(localStorage.getItem(yhd_cart)) || {}; function addToCart(goodsId) { if (cartData[goodsId]) { cartData[goodsId].count; } else { var product YHD.Goods.findById(goodsId); cartData[goodsId] { id: product.id, name: product.name, price: product.price, count: 1 }; } saveCart(); renderCart(); } function changeCount(goodsId, delta) { var item cartData[goodsId]; if (!item) return; item.count delta; if (item.count 0) { delete cartData[goodsId]; } saveCart(); renderCart(); } function saveCart() { localStorage.setItem(yhd_cart, JSON.stringify(cartData)); } function updateTotal() { var total 0; for (var key in cartData) { total cartData[key].price * cartData[key].count; } return Math.round(total * 100) / 100; }这段代码里最需要理解的是cartData这个对象的数据结构。它以商品id作为 key对应的 value 是{ id, name, price, count }。这种结构的好处是查找和更新都走对象键名时间复杂度是 O(1)不用每次遍历整个数组。addToCart里有两个细节容易忽略当购物车中已有该商品时只做count不重复插入记录当商品数量减到 0 时直接delete该键保持数据干净。saveCart把整个对象序列化后写入 localStorage这是整套代码的持久化核心刷新页面后购物车数据不会丢。我在实际项目里看到不少新人会把购物车写成「数组 push」方式结果查重时被迫用indexOf遍历性能和可读性都差。这份代码直接给你看到了一种更合理的方案值得记下来。4. 部署运行与联调让本地代码真正跑起来代码不是拿来看的是拿来跑的。这一章我按自己实际操作的顺序把从解压到页面能点、能加购、能结算的流程完整走一遍包括本地服务怎么起、接口怎么对、mock 数据什么时候该换。4.1 本地环境依赖与启动步骤这套代码没有任何第三方依赖不需要 npm install不需要 package.json。它只需要一个静态文件服务把目录托管起来。我用的是 VS Code 的 Live Server 扩展也可以用 Python 自带的 HTTP 服务# 进入项目根目录 cd yihaodian # 用 Python 启动静态文件服务默认监听 8000 端口 python -m http.server 8000启动后浏览器访问http://localhost:8000看到商品列表页面就说明一切正常。注意一个习惯问题直接从文件系统双击 index.html 也能打开但浏览器对 file:// 协议下的某些资源加载有限制而且 localStorage 在某些浏览器里对 file:// 页面是不稳定的强烈建议走 HTTP 方式。启动过程中如果页面空白按 F12 打开开发者工具切到 Console 面板。最常见的报错是资源加载路径不对比如看到Failed to load resource: net::ERR_FILE_NOT_FOUND这说明 css 或 js 的路径没有对上目录结构。4.2 接口对接与 mock 数据切换这套代码本身没有接后端接口商品数据直接写在 goods.js 里。真实项目里数据必然来自后端接口所以联调的时候要做两件事把静态数组替换成 fetch 请求同时保留一份 mock 数据兜底。// 替换 goods.js 里 renderGoods 的数据来源 function loadGoods() { var mode window.LOCAL_MOCK ? mock : api; if (mode mock) { renderGoods(productList); return; } fetch(/api/goods) .then(function(res) { return res.json(); }) .then(function(data) { renderGoods(data); }) .catch(function() { // 接口挂了退回本地数据 renderGoods(productList); }); }这里的window.LOCAL_MOCK就相当于一个总开关本地开发时在 HTML 里定义它并置为 true就走 mock联调时删掉这行定义请求就会打到真实接口。catch里退回本地数据是兜底策略避免接口异常导致页面完全白屏。我建议你在联调时用一个浏览器插件来模拟接口响应比如在 Network 面板里右键某个请求选择 Mock 响应不改代码就能验证前端对各种返回值的处理。这样比你频繁改 JS 里的开关快得多。5. 避坑与排查这套代码最常见的五个问题老代码结构简单但踩坑一点都不少。我把实际跑这套代码时容易踩到的五个坑按「现象→原因→解决」的方式记录下来你照着排查能省很多时间。5.1 中文乱码现象页面上的中文全部变成「锟斤拷」一类的乱码。原因HTML 和 JS 文件的编码不一致。老项目大多采用 GBK 编码但如果文件被某些编辑器默认保存为 UTF-8浏览器按 GBK 解析就会出现乱码。解决在 index.html 的 head 里保留meta charsetgbk同时确认 js 和 css 文件都通过编辑器右下角编码菜单转成 GBK。如果不想继续用 GBK最简单的办法是统一全部文件为 UTF-8并把 charset 改成utf-8。5.2 商品列表正常但加购按钮没反应现象列表渲染出来了但点击「加入购物车」没有任何反馈。原因事件绑定在初始 DOM 上但商品列表是通过innerHTML动态渲染的事件监听器没有绑定到动态生成的按钮上。解决把事件绑定向父级容器委托。常见做法是给 goods-list 容器绑 click用event.target.closest(.js-add-cart)判断点击落在哪个按钮上。这份代码里如果只绑了静态节点就会出现这个问题。5.3 刷新页面后购物车数据丢失现象加购成功但一刷新购物车清空了。原因浏览器在 file:// 协议下对 localStorage 支持不稳定或者代码里根本没有调用saveCart()。解决确认访问方式是 http:// 而不是 file://然后在 cart.js 里查一下addToCart最后是否执行了saveCart()每次修改cartData后必须持久化一次。5.4 价格计算出现 0.30000000000000004现象购物车里两个商品价格相加结果尾部冒出长串小数。原因JavaScript 浮点数直接用*和计算时存在精度损耗比如 0.1 0.2 的结果不是 0.3。解决先乘 100 转整数计算再除 100 回显。代码里的updateTotal()用了Math.round(total * 100) / 100这就是标准的处理方式。你要是自己新增了折扣逻辑记住同样的原则。5.5 后端字段名对不上页面显示 undefined现象接口联调后商品名显示undefined价格不显示。原因后端返回的字段是goods_name而前端模板里用的是name字段名不一致。解决在 fetch 的.then里做一层数据映射把后端字段名统一改成前端需要的结构不要在前端模板里到处改字段名。比如{ name: raw.goods_name, price: raw.goods_price }。6. 把这份代码改造成自己的项目三个切实可行的做法看完这份 1号店代码如果只是会跑价值只发挥了一半。真正有用的是把它拆开、改造、吸收成你的东西。我分享三个我实际用过的改造方向。第一个做法是模块化重写。把 goods.js、cart.js 里的方法按功能拆出来用 ES Module 的export/import替代原来的全局命名空间。这样每个文件职责更清晰测试也好写。你可以用 Vite 起一个最小工程把现有代码迁进去不动业务逻辑仅改引入方式。第二个做法是把 DOM 操作封装成工具函数。老代码里到处是document.getElementById和element.innerHTML 你可以借鉴现代框架的思路封装一个el()方法和一个render()方法让数据和视图的映射关系更直观。做好这一步后续你要改成 Vue 或 React 会轻松很多。第三个做法是把商品数据从静态数组改为接口驱动。我上面给的LOCAL_MOCK开关模式就是最实用的过渡方案——开发用本地数据部署切接口中间留一个兜底。这套模式放任何项目里都能用。最后说一个我的血泪习惯从那以后我每次拿到别人的代码包第一件事永远是开 Console 看有没有红色报错然后完整走一遍「列表→加购→改数量→刷新→结算」的核心链路确认数据在每一步都稳定。顺序对了排错就快了。这套代码的完整逻辑和踩坑点都在上面了希望你少走我走过的弯路希望帮到你。本文还有配套的精品资源点击获取
返回列表