简介:这份微信小程序商城完整源码面向希望快速搭建微信电商应用的开发者与小型商家,提供从商品展示、购物车、订单管理到支付与用户互动的整套实现,适合具备一定前端基础、想通过真实项目理解小程序技术栈的学习者。压缩包共60个文件,约412KB,以24个png界面素材、9个wxss样式表、9个js逻辑脚本、7个json配置、7个wxml结构文件为主,另附说明文档,覆盖页面结构、样式与业务逻辑三层。源码按pages页面目录、app全局配置、utils工具库、models数据模型与components自定义组件组织,可对照理解商品详情、购物车、订单确认等页面的设计与微信支付接口集成方式。目前已有7737人学习下载,适合作为小程序商城开发的入门参照与二次开发起点。
1. 微信小程序商城完整源码:一套能直接跑通交易闭环的工程底子
手上接过一个需求,客户要两周内出一个能下单、能付款、能看订单的微信小程序商城。从零写不现实,我翻出一套完整的商城源码包,改配置、换素材、接支付,第三天就跑通了从商品详情到支付回调的全链路。这类源码的价值不在于“省几行代码”,而在于它把商品、购物车、订单、支付、售后这条交易闭环的骨架搭好了,你只需要往里面填业务。适合谁?一是接私活要快速交付的独立开发者,二是想学小程序电商工程结构的前端,三是有现成商品数据、只缺一套前端壳子的小团队。下面按我实际拆包的顺序讲:结构怎么读、环境怎么起、支付和订单怎么接、哪些地方一改就翻车。
2. 拆包先看目录:页面栈、组件层与数据流怎么分层
拿到源码别急着npm install,先花二十分钟把目录结构读明白,后面改起来才不会牵一发动全身。这套商城的典型分层是:pages放页面、components放复用组件、utils放请求封装和工具函数、config或env放环境变量、mock放本地假数据。读目录的本质是搞清楚“一个订单从点击到落库,数据在哪几层之间流转”。
2.1 页面栈与 tabBar 的对应关系
先打开app.json,看pages数组和tabBar配置。首页、分类、购物车、我的这四个 tab 基本是固定的,剩下的商品详情、订单确认、订单列表、地址管理都是普通页面。重点看pages数组第一项——它是启动页,很多源码默认放的是首页,但如果你要做活动落地页,改这里比改跳转逻辑省事。
{ "pages": [ "pages/index/index", "pages/category/category", "pages/cart/cart", "pages/user/user", "pages/goods/detail", "pages/order/confirm", "pages/order/list" ], "tabBar": { "list": [ { "pagePath": "pages/index/index", "text": "首页" }, { "pagePath": "pages/category/category", "text": "分类" }, { "pagePath": "pages/cart/cart", "text": "购物车" }, { "pagePath": "pages/user/user", "text": "我的" } ] } }这段配置决定了小程序的导航骨架。pages数组的顺序影响预加载优先级,把高频页面往前放能减少白屏;tabBar.list的pagePath必须和pages里的路径完全一致,少一个斜杠都会导致 tab 点击无响应。我一般会把order/confirm紧跟在cart后面,因为从购物车结算跳转最频繁。
2.2 请求封装层:统一 baseURL 与拦截器
商城源码里最值得先读的是utils/request.js这类文件。它通常封装了wx.request,统一处理 baseURL、token 注入、错误码。读它你就知道后端接口约定长什么样,改域名只改一处。
// utils/request.js const BASE_URL = 'https://api.example.com' // 换成自己的后端域名 function request(options) { return new Promise((resolve, reject) => { wx.request({ url: BASE_URL + options.url, method: options.method || 'GET', data: options.data || {}, header: { 'content-type': 'application/json', 'Authorization': wx.getStorageSync('token') || '' // 登录后写入 }, success(res) { if (res.statusCode === 200 && res.data.code === 0) { resolve(res.data.data) } else if (res.data.code === 401) { wx.navigateTo({ url: '/pages/login/login' }) // token 失效跳登录 reject(res.data) } else { wx.showToast({ title: res.data.msg || '请求失败', icon: 'none' }) reject(res.data) } }, fail(err) { wx.showToast({ title: '网络异常', icon: 'none' }) reject(err) } }) }) } module.exports = { request }逻辑说明:所有页面通过request({ url, method, data })调用接口,baseURL 和 token 只在这一层维护。参数上,code === 0是这套源码约定的成功码,你接自己后端时要么改后端返回结构,要么改这里的判断;401分支负责登录态失效的兜底跳转,这是电商场景必须有的,否则用户下单到一半 token 过期会卡死。注意wx.getStorageSync('token')的 key 要和登录页写入时保持一致,这是最常见的低级错误。
2.3 组件层:商品卡片与数量选择器
components目录里通常有goods-card、num-stepper、empty这类组件。商品卡片接收一个goods对象,数量选择器通过properties接收value、通过triggerEvent回传变化。读组件要看它的properties定义,那是页面传参的契约。
// components/num-stepper/num-stepper.js Component({ properties: { value: { type: Number, value: 1 }, min: { type: Number, value: 1 }, max: { type: Number, value: 99 } }, methods: { onMinus() { if (this.data.value <= this.data.min) return this.setData({ value: this.data.value - 1 }) this.triggerEvent('change', { value: this.data.value }) }, onPlus() { if (this.data.value >= this.data.max) return this.setData({ value: this.data.value + 1 }) this.triggerEvent('change', { value: this.data.value }) } } })min和max是边界保护,购物车里min设 1,库存紧张时max要动态传库存数。triggerEvent('change')把新值抛给父页面,父页面在bind:change里更新购物车数据。这里有个容易忽略的点:组件内部setData改了value,父页面如果没同步更新传入的value,下次渲染会回退,所以父页面收到事件后必须回写。
3. 本地跑通:开发者工具配置、mock 数据与真机预览
目录读懂了,下一步是让它在你机器上跑起来。这一步的目标很明确:不接后端也能看到完整页面,接了后端能走通一次下单。很多人卡在“编译报错”或“页面空白”,其实八成是配置项没对上。
3.1 项目配置与合法域名
用开发者工具导入项目根目录,工具会读project.config.json。重点看appid——源码里通常是占位符,你要换成自己小程序的 appid,否则真机预览会失败。然后看setting.urlCheck,本地调试阶段可以关掉域名校验,但上线前必须打开并在后台配置合法域名。
{ "appid": "wx0000000000000000", "projectname": "mall-demo", "setting": { "urlCheck": false, "es6": true, "minified": true }, "compileType": "miniprogram" }urlCheck: false只建议在开发阶段用,它让你请求未备案的本地接口;es6: true开启 ES6 转 ES5,源码里用了Promise、箭头函数,关掉会编译失败。上线前把urlCheck改回true,并在小程序后台把https://api.example.com加进 request 合法域名,否则真机一片红。
3.2 mock 数据切换与接口对齐
多数商城源码带mock目录或config/index.js里的开关。常见做法是设一个USE_MOCK常量,为true时请求走本地假数据,为false时走真实接口。我一般先把 mock 打开,确认页面渲染正常,再逐个接口切真实后端。
// config/index.js const ENV = { USE_MOCK: true, // 本地调试先开 mock BASE_URL: 'https://api.example.com' } // utils/request.js 里加一层判断 const { USE_MOCK, BASE_URL } = require('../config/index') function request(options) { if (USE_MOCK) { return Promise.resolve(require('../mock' + options.url + '.js')) } // ...真实请求逻辑 }这样切的好处是页面代码一行不用改,只动一个布尔值。参数上,mock 文件的路径要和接口路径对应,比如/goods/list对应mock/goods/list.js,导出默认对象即可。切真实接口时按页面顺序来:先首页商品列表,再详情,再购物车,最后订单和支付——支付放最后是因为它依赖登录态和真实金额,mock 阶段验证不了。
3.3 真机预览与基础库版本
开发者工具里点“预览”生成二维码,手机扫码即可。真机预览最常见的两个坑:一是基础库版本,源码用了较新的 API(如wx.getUserProfile的替代方案、chooseMedia),手机微信版本低会报“API 不存在”;二是project.config.json里的libVersion设得太高,工具模拟器能跑、真机跑不了。我一般把libVersion设成2.20.0左右,兼容性和新特性兼顾。
提示:真机预览前先在工具里点“清缓存 → 全部清除”,否则旧的 storage(尤其是 token 和购物车)会干扰判断,出现“明明改了代码页面没变”的玄学现象。
4. 交易闭环:登录态、购物车与支付回调怎么接
页面能跑只是壳子,商城源码真正的价值在交易链路。这一章按“登录 → 加购 → 下单 → 支付 → 回调”的顺序拆,每一步都对应源码里的具体文件和参数。接不通的地方,多半是登录态没串起来或者支付参数签名对不上。
4.1 登录态:code 换 token 的完整链路
小程序登录不是拿账号密码,而是wx.login拿code,传给后端换openid和自定义token。源码里通常在app.js的onLaunch或登录页做这件事。关键是 token 存哪、什么时候带、失效怎么办。
// pages/login/login.js Page({ onLoad() { wx.login({ success: async (res) => { if (!res.code) return const data = await request({ url: '/auth/login', method: 'POST', data: { code: res.code } }) wx.setStorageSync('token', data.token) wx.setStorageSync('userInfo', data.userInfo) wx.switchTab({ url: '/pages/user/user' }) } }) } })res.code有效期五分钟且只能用一次,所以拿到后要立刻发后端,不能缓存。后端用 code 加 appid、secret 调微信接口换openid,再签发自己的 token 返回。wx.setStorageSync('token', ...)的 key 必须和request.js里读取的 key 一致,这是登录态串不起来的第一大原因。另外switchTab只能跳 tab 页,跳普通页要用navigateTo,用错会静默失败。
4.2 购物车:本地存储与后端同步的取舍
购物车有两种实现:纯本地storage和后端同步。源码里常见的是“未登录存本地、登录后合并到后端”。读pages/cart/cart.js看它的onShow逻辑——每次进购物车都重新拉数据还是读缓存,决定了你改库存时的行为。
// pages/cart/cart.js 核心逻辑 Page({ data: { list: [] }, onShow() { const token = wx.getStorageSync('token') if (token) { this.fetchCartFromServer() // 已登录走后端 } else { this.setData({ list: wx.getStorageSync('cart') || [] }) // 未登录读本地 } }, async fetchCartFromServer() { const list = await request({ url: '/cart/list' }) this.setData({ list }) }, onNumChange(e) { const { id, value } = e.detail const list = this.data.list.map(item => item.id === id ? { ...item, num: value } : item ) this.setData({ list }) if (wx.getStorageSync('token')) { request({ url: '/cart/update', method: 'POST', data: { id, num: value } }) } else { wx.setStorageSync('cart', list) } } })onShow而不是onLoad是关键——从详情页加购返回购物车,onLoad不会重新触发,页面显示的还是旧数据,这是新手最常翻的车。数量变化时先更新本地data再异步同步后端,保证 UI 即时响应;未登录时写回storage。注意合并逻辑:登录后要把本地购物车 POST 给后端做 merge,否则用户登录前加的商品会丢,源码里如果没写这段,得自己补。
4.3 下单与支付:统一下单参数与回调验签
下单流程是:订单确认页提交商品、地址、金额 → 后端生成订单号并调微信统一下单 → 返回prepay_id和签名参数 → 前端wx.requestPayment拉起支付 → 微信回调后端 → 后端改订单状态。前端只负责拉起,金额和签名必须后端算,前端传的金额只能做展示。
// pages/order/confirm.js 支付部分 async onPay() { const order = await request({ url: '/order/create', method: 'POST', data: { goods: this.data.goods, addressId: this.data.addressId } }) // order 里含 timeStamp、nonceStr、package、signType、paySign wx.requestPayment({ timeStamp: order.timeStamp, nonceStr: order.nonceStr, package: order.package, signType: order.signType || 'RSA', paySign: order.paySign, success: () => { wx.redirectTo({ url: '/pages/order/list?status=paid' }) }, fail: (err) => { if (err.errMsg.includes('cancel')) { wx.showToast({ title: '已取消支付', icon: 'none' }) } else { wx.showToast({ title: '支付失败', icon: 'none' }) } } }) }package字段格式是prepay_id=xxx,paySign由后端用商户私钥签名,前端原样透传,绝不能在前端拼签名——私钥泄露是重大事故。signType现在推荐RSA,老源码里可能是MD5,接新商户号时要改。success回调只代表用户完成了支付动作,不代表钱到账,订单状态必须以微信服务器回调后端的结果为准,所以跳转后订单列表要重新拉一次状态,不能直接信前端。
注意:支付回调地址必须在商户平台配置且公网可达,本地调试收不到回调。常见做法是用内网穿透工具把本地端口映射出去,回调里做验签和幂等处理(同一订单号重复回调只处理一次),否则会出现重复发货。
5. 避坑排查:五个让商城源码跑不起来的高频问题
源码跑不通,九成不是代码写错,而是环境和配置对不上。下面五条是我拆这类包时反复遇到的,按“现象 → 原因 → 解决”记,能省不少排查时间。
5.1 页面白屏但编译无报错
现象:工具里编译成功,模拟器一片白,控制台无红色错误。原因:多半是app.json里pages路径写错,或启动页onLoad里同步抛了异常被吞掉。解决:先把pages数组只留首页一项试跑,确认路径;再在app.js的onError里打日志,把被吞的异常捞出来。我遇到过require路径大小写不一致,Windows 不报错、真机直接白屏。
5.2 请求全部 404 或跨域
现象:所有接口报 404,或工具提示“不在以下 request 合法域名列表中”。原因:BASE_URL没改,或urlCheck开着但域名没配。解决:开发阶段把urlCheck设false,确认BASE_URL指向自己的后端;上线前在后台配好https域名。注意小程序不支持http,本地接口要么用穿透工具给个https,要么全程 mock。
5.3 登录后仍提示未登录
现象:登录成功、token 也存了,但下单时后端返回 401。原因:request.js读 token 的 key 和登录页写的 key 不一致,或 header 字段名后端要的是token而前端发的是Authorization。解决:全局搜setStorageSync('token'和getStorageSync('token',确认 key 统一;再对一遍后端接口文档的 header 约定。这类问题用工具 Network 面板看请求头最快。
5.4 支付拉起失败,报“签名错误”
现象:wx.requestPayment直接 fail,errMsg含sign或paySign。原因:后端签名用的密钥、signType和商户号不匹配,或timeStamp传成了数字而非字符串。解决:确认商户号、API 密钥、证书三者对应同一套;timeStamp必须是字符串;signType与商户平台开通的一致。签名问题前端改不了,必须后端对参数重算,把后端算签名的入参打日志逐字段比对。
5.5 真机能用模拟器不能用
现象:手机扫码一切正常,开发者工具模拟器报 API 不存在或样式错乱。原因:模拟器基础库版本和手机微信版本不一致,或用了模拟器不支持的 API(如部分chooseMedia能力)。解决:工具里“详情 → 本地设置 → 调试基础库”调到和手机接近的版本;样式问题多半是rpx和px混用,模拟器窗口尺寸和真机不同导致,统一用rpx并检查flex布局的min-height。
6. 二次开发收口:把源码改成自己项目的三个动作
源码能跑通只是起点,真正交付要把它改成“自己的项目”。我一般做三个动作:换主题变量、抽业务配置、加一层环境区分。这套流程走完,同一份源码能复用到不同客户,不用每次从头改。
6.1 主题色与设计变量集中管理
商城源码的样式散在各页面wxss里,改主题色最怕漏改。先全局搜主色值(比如#ff5000),把它抽到app.wxss的 CSS 变量里,页面里引用变量。小程序基础库 2.11 以上支持 CSS 变量,老版本就用@import一个theme.wxss。
/* app.wxss */ page { --primary-color: #ff5000; --text-main: #333333; --bg-page: #f5f5f5; } /* 页面里引用 */ .price { color: var(--primary-color); }抽完之后改主题只动app.wxss一处。注意page选择器上的变量对自定义组件默认不生效,组件里要用:host或把变量定义在组件根节点,这是 CSS 变量在小程序里的边界。
6.2 业务配置外置:店铺信息、客服、分享文案
把店铺名、客服电话、分享标题这类会变的东西集中到config/business.js,页面里require引用。这样换客户只改一个文件,不用满项目搜字符串。
| 配置项 | 示例值 | 使用位置 |
|---|---|---|
| shopName | 某某优选 | 首页标题、分享 |
| servicePhone | 400-000-0000 | 我的页、客服按钮 |
| shareTitle | 好物精选,进来看看 | 各页 onShareAppMessage |
| freeShipping | 99 | 购物车凑单提示 |
表格里freeShipping是包邮门槛,购物车页用它算“还差多少包邮”,这类业务数字外置后运营改起来不用找开发。
6.3 环境区分:开发、测试、生产三套配置
最后一步是把config/index.js改成按环境导出,用__wxConfig.envVersion或构建时注入区分。开发连测试后端、生产连正式后端,避免测试数据污染线上。
// config/index.js const env = __wxConfig.envVersion // develop / trial / release const configs = { develop: { BASE_URL: 'https://test-api.example.com', USE_MOCK: false }, trial: { BASE_URL: 'https://test-api.example.com', USE_MOCK: false }, release: { BASE_URL: 'https://api.example.com', USE_MOCK: false } } module.exports = configs[env] || configs.develop__wxConfig.envVersion由微信运行时注入,开发版是develop、体验版trial、正式版release,不用自己判断。这样同一份代码上传三个版本自动连不同后端,省掉手动改配置再上传的后悔药环节。
这套源码我前后改过几个项目,最大的教训是:拿到包先别动业务代码,花半天把目录、请求层、登录态、支付链路读一遍,把环境配置跑通,再动手改。从那以后我每次拆新源码包,都强制先走一遍“mock 跑通 → 真机预览 → 支付沙箱验证”这三步,确认骨架没问题再往里填业务,翻车率低很多。希望帮到你。
本文还有配套的精品资源,点击获取