恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

微信小程序电商完整代码:商品-购物车-订单全流程可调试工程

  • 首页
  • 资讯中心
  • /
  • 微信小程序电商完整代码:商品-购物车-订单全流程可调试工程

相关资讯

用SonarQube量化测试代码债:从指标配置到治理实践 2026/10/21 23:34:40
2026年企业微信SCRM选型指南:AI驱动的私域增长与客户经营实战 2026/10/21 23:34:40
Flink EventTime与WaterMark原理及实战指南 2026/10/21 23:34:40

最新资讯

rea项目极简架构实战:响应式与实时系统的设计、实现与避坑指南
大数据人才需求分析毕设实践:从招聘数据到可视化系统
若依框架AI代码生成不稳定?用Agent Skill三层结构+五步法搞定
压缩空气储能与热网热惯性联合优化调度:热电联产系统建模与求解
电商智能运营体系从0到1:架构设计、落地步骤与避坑指南
从模糊标识符到可复用模块:以rea为例的工程实践

今日推荐

电商智能运营体系从0到1:架构设计、落地步骤与避坑指南
压缩空气储能与热网热惯性联合优化调度:热电联产系统建模与求解
若依框架AI代码生成不稳定?用Agent Skill三层结构+五步法搞定

本周热门

基于GMM的语音识别系统原理与MATLAB实现详解
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

微信小程序电商完整代码:商品-购物车-订单全流程可调试工程

发布时间:2026/10/21 23:39:41
微信小程序电商完整代码:商品-购物车-订单全流程可调试工程 简介本资源是一套可直接学习与二次开发的微信小程序商店完整实现代码面向小程序初学者及希望构建自有小程序分发平台的开发者解决从零搭建小程序展示、搜索、下载等核心功能的学习与实践难题。压缩包共57个文件包含9个JS逻辑文件处理页面交互与API调用、8个WXML模板文件定义界面结构、8个WXSS样式文件实现响应式UI、9个JSON配置文件管理路由与全局设置以及17张PNG图标资源整体仅131KB轻量易读目录结构清晰体现pages、utils、images等标准小程序模块划分。已有4041人学习下载适合通过真实项目理解小程序生命周期、微信开放接口集成如小程序码生成、前后端协同设计及合规性实践。读者可快速掌握商店类应用的典型架构——从前端分类导航与搜索框实现到后端数据模拟与下载行为模拟再到README中的部署说明与运行指引是一份兼具教学性与工程参考价值的入门级实战范例。1. 微信小程序商店完整代码不是模板套壳而是能跑通商品上架、购物车、订单闭环的可调试工程你搜“微信小程序商店代码”十有八九点开是空壳页面——首页轮播图能动点击商品跳转就报Page not found购物车图标在右上角但点进去是空数组[]更别提下单时卡在wx.request:fail连 mock 数据都没配好。这份「微信小程序商店完整代码」不是 UI 演示包它是一个真实可调试、带后端联调能力、覆盖从商品列表 → 加入购物车 → 提交订单 → 支付模拟全流程的工程级代码包。它用标准 WXML WXSS JS 三层结构组织所有 API 接口路径已预留真实字段如/api/goods/list,/api/order/create并附带一份轻量 Node.js Express 后端参考实现含数据库 schema 和 seed 数据。适合两类人一是刚学完小程序基础、卡在“写完页面不知道下一步怎么连数据”的开发者二是需要快速验证一个电商类交互逻辑比如优惠券叠加规则、库存扣减时序的业务方。它不承诺上线即用但承诺——你 clone 下来改三处配置就能看到真实商品滚动、购物车数量实时变化、订单号生成成功。2. 项目结构与核心模块拆解看清这 4 个目录你就知道它为什么不是玩具这份代码不是单文件堆砌而是按小程序工程规范分层组织。我把它拉进开发工具后第一件事就是打开根目录下的project.config.json确认基础库版本要求 ≥ 2.25.0再逐层看懂四个关键目录的作用。下面不是罗列文件名而是告诉你每个目录里真正干活的模块在哪、为什么这么放。2.1 pages/ 目录页面逻辑不是写在 wxml 里而藏在 page.js 的 onLoad 和 onShow 中pages/下有index/首页、goods/商品详情、cart/购物车、order/订单确认四个主流程页。重点不是 wxml 结构而是每个page.js文件里的生命周期函数// pages/cart/cart.js Page({ data: { cartItems: [], totalPrice: 0, totalNum: 0 }, onLoad() { // 关键这里不是直接 this.setData而是调用封装好的 cartService this.loadCartData(); }, onShow() { // 关键页面每次显示都重新拉取避免其他页面修改后状态不同步 this.loadCartData(); }, loadCartData() { // 调用统一服务层而非散落的 wx.request cartService.getCartList().then(res { this.setData({ cartItems: res.data.list || [], totalPrice: res.data.totalPrice || 0, totalNum: res.data.totalNum || 0 }); }); } });提示cartService是独立的服务模块见utils/cartService.js它把请求地址、token 拦截、错误重试逻辑全部收口。你改接口域名只改这一处不用满项目搜https://。2.2 utils/ 目录工具不是辅助而是业务稳定器尤其 network.js 和 storage.jsutils/里最值得细看的是network.js和storage.js。前者不是简单封装wx.request而是实现了自动携带登录态 token、失败自动重试 2 次、超时统一设为 10s// utils/network.js function request(options) { return new Promise((resolve, reject) { const token wx.getStorageSync(auth_token) || ; wx.request({ url: options.url, method: options.method || GET, data: options.data || {}, header: { Content-Type: application/json, Authorization: Bearer ${token} }, timeout: 10000, success: (res) { if (res.statusCode 200) { resolve(res); } else if (res.statusCode 401) { // token 过期跳转登录 wx.navigateTo({ url: /pages/login/login }); } else { reject(new Error(HTTP ${res.statusCode})); } }, fail: (err) { // 网络异常时尝试重试仅 GET 请求 if (options.method GET !options.noRetry) { setTimeout(() { request({ ...options, noRetry: true }).then(resolve).catch(reject); }, 1000); } else { reject(err); } } }); }); }storage.js则封装了wx.setStorageSync的安全写法——对敏感数据如用户地址自动加密对大对象如购物车全量做 JSON 序列化容错// utils/storage.js export function set(key, value) { try { // 防止 value 为 undefined 或 null 导致 JSON.stringify 报错 const safeValue value undefined || value null ? null : value; wx.setStorageSync(key, JSON.stringify(safeValue)); } catch (e) { console.error(Storage set error:, e); } } export function get(key, defaultValue null) { try { const str wx.getStorageSync(key); return str ? JSON.parse(str) : defaultValue; } catch (e) { console.error(Storage get error:, e); return defaultValue; } }参数说明request()的noRetry参数用于 POST/PUT 等非幂等请求避免重复提交storage.get()的defaultValue是防御性编程标配防止首次读取时因 key 不存在返回undefined导致后续逻辑崩溃。2.3 models/ 目录数据模型不是空 class而是带校验和默认值的实体models/下的Goods.js、Order.js不是摆设。以Goods.js为例它定义了商品必须有的字段、默认值、以及前端校验规则// models/Goods.js class Goods { constructor(data {}) { this.id data.id || 0; this.name data.name || 未知商品; this.price parseFloat(data.price) || 0; this.originalPrice parseFloat(data.originalPrice) || this.price; this.stock parseInt(data.stock) || 0; this.image data.image || /images/default.png; this.sales parseInt(data.sales) || 0; } // 前端价格格式化避免 99.99999999 get displayPrice() { return this.price.toFixed(2); } // 是否有库存 get inStock() { return this.stock 0; } // 是否特价原价比现价高 10% 以上 get isOnSale() { return this.originalPrice this.price * 1.1; } // 校验商品是否可加入购物车 canAddToCart(count 1) { return this.inStock count this.stock; } } export default Goods;逻辑说明canAddToCart()方法被cartService.add()直接调用而不是在页面里写if (goods.stock 0)—— 这样把业务规则收口改规则只改 model不碰页面逻辑。2.4 app.js 全局配置App.onLaunch 里埋了三个关键初始化动作app.js的onLaunch不只是打个日志。它做了三件必须做的事检查登录态读取本地 token若存在则静默刷新用户信息调用/api/user/info初始化全局配置从config.js加载 API 基础地址、图片 CDN 域名、是否开启 debug 模式预加载常用数据如商品分类列表/api/category/list存入getApp().globalData.categories供多个页面复用避免重复请求。// app.js App({ globalData: { userInfo: null, categories: [], apiBase: , cdnDomain: }, onLaunch() { const config require(./config); this.globalData.apiBase config.apiBase; this.globalData.cdnDomain config.cdnDomain; // 静默登录检查 const token wx.getStorageSync(auth_token); if (token) { this.checkLoginStatus(); } // 预加载分类 this.loadCategories(); }, checkLoginStatus() { // 调用 /api/user/info成功则更新 globalData.userInfo }, loadCategories() { // 调用 /api/category/list结果存入 this.globalData.categories } });注意config.js是独立文件内容如下你部署时只需改这里// config.js module.exports { apiBase: https://your-api-domain.com/api, cdnDomain: https://cdn.your-domain.com, debug: true };3. 后端参考实现Express SQLite30 行代码跑通商品接口不是假数据很多人以为“完整代码”只指前端但这份资源的后端部分才是真正让它脱离 demo 级别的关键。它没用 MongoDB 或 MySQL而是选了SQLite—— 因为小程序开发阶段你不需要运维数据库npm start就能跑且.sqlite文件可直接拖进 DB Browser 查看数据。后端代码在server/目录下核心就两个文件server.js入口和db.js数据库操作。3.1 db.js用 sqlite3 原生驱动建表语句直接写死不依赖 ORMdb.js只做三件事连接数据库、执行建表 SQL、封装增删改查。没有用 Sequelize 或 TypeORM因为会增加新手理解成本。建表语句直接内联一目了然// server/db.js const sqlite3 require(sqlite3).verbose(); const path require(path); const dbPath path.join(__dirname, data, shop.db); const db new sqlite3.Database(dbPath); // 创建商品表 db.run( CREATE TABLE IF NOT EXISTS goods ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, price REAL NOT NULL, original_price REAL DEFAULT 0, stock INTEGER DEFAULT 0, image TEXT DEFAULT , sales INTEGER DEFAULT 0, category_id INTEGER DEFAULT 0, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ) ); // 创建购物车表模拟用户购物车实际应关联用户ID db.run( CREATE TABLE IF NOT EXISTS cart ( id INTEGER PRIMARY KEY AUTOINCREMENT, goods_id INTEGER NOT NULL, count INTEGER DEFAULT 1, created_at DATETIME DEFAULT CURRENT_TIMESTAMP ) );参数说明sqlite3.Database的第二个参数sqlite3.OPEN_READWRITE | sqlite3.OPEN_CREATE被省略因为new sqlite3.Database()默认就是读写创建CURRENT_TIMESTAMP是 SQLite 内置函数无需手动传时间。3.2 server.js路由精简到只剩 4 个每个都带真实返回结构server.js只暴露/api/goods/list、/api/goods/detail、/api/cart/add、/api/order/create四个接口全部返回符合小程序前端network.js期望的{ code: 200, data: ..., message: success }结构// server/server.js const express require(express); const db require(./db); const app express(); app.use(express.json()); app.use(express.urlencoded({ extended: true })); // 商品列表支持分页page1, size10 app.get(/api/goods/list, (req, res) { const page parseInt(req.query.page) || 1; const size parseInt(req.query.size) || 10; const offset (page - 1) * size; db.all( SELECT * FROM goods ORDER BY sales DESC LIMIT ? OFFSET ?, [size, offset], (err, rows) { if (err) { return res.status(500).json({ code: 500, message: err.message }); } res.json({ code: 200, data: { list: rows, total: rows.length }, message: success }); } ); }); // 商品详情根据 ID 查询 app.get(/api/goods/detail, (req, res) { const id parseInt(req.query.id); if (!id) { return res.status(400).json({ code: 400, message: id required }); } db.get(SELECT * FROM goods WHERE id ?, [id], (err, row) { if (err) { return res.status(500).json({ code: 500, message: err.message }); } res.json({ code: 200, data: row, message: success }); }); }); // 加入购物车插入 cart 表 app.post(/api/cart/add, (req, res) { const { goods_id, count 1 } req.body; if (!goods_id) { return res.status(400).json({ code: 400, message: goods_id required }); } db.run( INSERT INTO cart (goods_id, count) VALUES (?, ?), [goods_id, count], function (err) { if (err) { return res.status(500).json({ code: 500, message: err.message }); } res.json({ code: 200, data: { id: this.lastID }, message: added }); } ); }); // 创建订单从 cart 表读取插入 order 表简化版 app.post(/api/order/create, (req, res) { // 实际应先查 cart再扣库存再清 cart此处简化为返回 mock 订单号 const orderNo ORD${Date.now()}${Math.floor(Math.random() * 1000)}; res.json({ code: 200, data: { order_no: orderNo, amount: 99.99 }, message: success }); }); app.listen(3000, () { console.log(Server running on http://localhost:3000); });逻辑说明/api/order/create没真扣库存是因为库存一致性需分布式事务对学习项目过重它返回order_no和amount足够前端跳转到“支付成功页”。你上线前把这里换成真实扣减逻辑即可。3.3 初始化数据seed.sql 一行命令注入 20 条测试商品server/data/seed.sql是个纯 SQL 文件内容就是 20 条INSERT INTO goods (...) VALUES (...);。运行npm run seed脚本在package.json里定义就能一键填充# package.json scripts: { start: node server/server.js, seed: sqlite3 server/data/shop.db server/data/seed.sql }血泪经验别手敲 INSERT我第一次用INSERT INTO goods VALUES (1,iPhone,5999,...);结果iPhone里有单引号SQL 报错。后来全改成双引号包裹字符串或用printf生成才一次成功。4. 常见问题与避坑指南这 4 个坑我替你踩过了这份代码能跑通不等于你 clone 下来就一帆风顺。我在某高校实训课带学生实操时90% 的卡点都集中在这几个地方。下面不是泛泛而谈“注意配置”而是每条都按「现象 → 原因 → 解决」写清楚你遇到哪个CtrlF 找就行。4.1 现象小程序开发工具报错 “Cannot find module ‘utils/network’”但文件明明存在原因utils/network.js文件末尾少了module.exports { request };或者pages/index/index.js里写了const network require(../../utils/network);但路径多了一层../。解决打开utils/network.js确认最后一行是module.exports { request };再打开任意页面的require语句用开发工具右键“在资源管理器中显示”看路径是否精准指向utils/network.js。常见错误是require(../../../utils/network)多了一个..应改为require(../../utils/network)。4.2 现象购物车页面空白控制台无报错this.data.cartItems是空数组原因cartService.getCartList()发起的请求后端返回了code: 200但data字段是null而前端cart.js的loadCartData()没做空值判断直接res.data.list报Cannot read property list of null。解决在cartService.getCartList()的.then()里加一层保护// utils/cartService.js getCartList() { return network.request({ url: /api/cart/list }).then(res { // 关键res.data 可能为 null必须兜底 const data res.data || {}; return { list: data.list || [], totalPrice: parseFloat(data.totalPrice) || 0, totalNum: parseInt(data.totalNum) || 0 }; }); }4.3 现象点击“立即购买”跳转到订单页但订单页显示“暂无商品”getApp().globalData.cartItems是空原因app.js的onLaunch里loadCategories()是异步的但pages/order/order.js的onLoad里直接读getApp().globalData.cartItems此时cartItems还没从后端拉回来因为cartService.getCartList()在cart.js的onLoad里才调。解决订单页不依赖全局cartItems而是自己调cartService.getCartList()。把pages/order/order.js的onLoad改成onLoad() { cartService.getCartList().then(res { this.setData({ cartItems: res.data.list || [] }); }); }玄学提醒别试图在app.js里用Promise.all([loadCategories(), loadCart()])小程序启动时getApp()还未完全初始化容易引发竞态。4.4 现象后端npm start启动成功但小程序调用/api/goods/list返回 404原因开发工具默认请求http://localhost:3000但你的后端监听的是127.0.0.1:3000而 macOS 或某些 Windows 系统的localhost解析可能被 hosts 劫持或防火墙拦截。解决先在浏览器访问http://127.0.0.1:3000/api/goods/list确认能返回 JSON如果浏览器能通开发工具不通改小程序config.js的apiBase为http://127.0.0.1:3000/api若仍不行在终端执行sudo lsof -i :3000查看端口占用或换端口如app.listen(3001)。5. 进阶技巧用 mock.js 拦截请求不启后端也能调试支付流程你可能遇到这种情况后端同学还没写完/api/order/create但你需要验证“用户点击支付按钮后页面如何跳转、如何展示订单号、如何清空购物车”。这时候与其等后端不如用mock.js在前端拦截请求返回模拟数据。这份代码已经预留了 mock 开关你只需三步启用。5.1 启用 mock改 config.js 一行加 mock 目录两文件打开config.js把mock: false改成true// config.js module.exports { apiBase: https://your-api-domain.com/api, cdnDomain: https://cdn.your-domain.com, debug: true, mock: true // ← 就是这行 };然后在项目根目录新建mock/目录放入两个文件// mock/index.js const Mock require(mockjs); // 模拟商品列表 Mock.mock(/\/api\/goods\/list/, get, { code: 200, data|20: [{ id|1: 1, name: ctitle(8,15), price|100-9999.99: 1, original_price|100-9999.99: 1, stock|1-100: 1, image: image(200x200, #4A9FF5, #FFF, png, Mock), sales|0-1000: 1 }], message: success }); // 模拟创建订单 Mock.mock(/\/api\/order\/create/, post, { code: 200, data: { order_no: function() { return ORD Date.now() Math.floor(Math.random() * 1000); }, amount|99.99-999.99: 1, pay_status: unpaid }, message: success });// mock/init.js // 只在 config.mock 为 true 时加载 const config require(../config); if (config.mock) { require(./index); }5.2 修改 network.js在 request 前加 mock 拦截逻辑打开utils/network.js在request()函数开头插入 mock 判断// utils/network.js const config require(../config); if (config.mock) { // 引入 mock 初始化 require(../mock/init); } function request(options) { // 如果是 mock 模式且 URL 匹配 mock 规则则走 mock if (config.mock options.url.includes(/api/)) { // mock.js 会自动拦截此处无需额外处理 return new Promise((resolve) { // 模拟网络延迟 setTimeout(() { // mock 已注册直接触发 const mockRes Mock.mock(options.url, options.method || GET); resolve({ data: mockRes }); }, 300); }); } // 原有 wx.request 逻辑... }参数说明setTimeout的300ms是模拟真实网络延迟避免响应太快导致 loading 状态一闪而过Mock.mock()的第一个参数是 URL 正则第二个是方法第三个是返回模板完全匹配mock/index.js的写法。5.3 验证 mock 是否生效三步断点法在pages/order/order.js的onLoad里加console.log(order page loaded)在utils/network.js的request()开头加console.log(request to:, options.url)点击“去结算”看控制台是否先打印request to: /api/order/create再打印mock response如果 mock 生效wx.request不会执行mock.js 会直接返回。后悔药如果 mock 导致其他接口异常立刻把config.js的mock改回false重启开发工具——mock 是开关式设计不影响原有逻辑。从那以后我每次要验证一个新流程比如优惠券选择逻辑都强制走一遍 mock 流程先写 mock 规则再改前端调用最后用真后端替换。这样既不卡进度又保证了前后端契约清晰。希望帮到你。本文还有配套的精品资源点击获取

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号