微信小程序商城前端源码合集:含分销、秒杀、积分、优惠券、订单全流程等全部业务页面

发布时间:2026/7/16 7:50:52
微信小程序商城前端源码合集:含分销、秒杀、积分、优惠券、订单全流程等全部业务页面 本文还有配套的精品资源点击获取简介这套微信小程序商城前端代码覆盖电商核心业务场景首页支持轮播与推荐位分类页按层级展示商品类目商品详情页集成规格选择、图文介绍与评价模块购物车支持多商品编辑与结算跳转订单管理包含待付款、待发货、待收货、已完成及售后全状态个人中心整合地址管理、会员信息、积分明细、优惠券领取与核销、余额查询分销功能提供推广员入驻、下级关系树、佣金记录与分享海报生成秒杀专区独立入口倒计时与库存同步控制另含搜索页、收藏夹、活动页、商品评价等高频页面。所有页面基于原生小程序框架开发使用JavaScript编写目录结构清晰如pages/goods_details、pages/order_list、pages/user_coupon等关键逻辑封装在util.js、api.js、store.js等工具文件中配套README.md说明启动方式支持开发者工具预览和真机调试开箱即用适合教学演示、课程设计或原型验证不适用于正式上线生产环境。1. 这不是“模板”而是一套跑通了真实电商逻辑的前端骨架我带过六届计算机专业毕业设计每年都有至少二十个学生卡在“小程序商城怎么才算真正跑起来”这个坎上。很多人以为下载个UI组件库、套几个页面就叫“完成商城”结果一到订单状态流转、优惠券叠加规则、分销佣金实时计算这些环节代码直接崩成一团乱麻。这套源码是我去年帮三个创业团队做MVP验证时沉淀下来的前端底座——它不追求炫酷动效但每个按钮点击后背后的数据流向、状态切换、边界校验都经得起推敲。关键词里写的“分销秒杀”“购物车订单”“优惠券积分”不是功能列表里的漂亮话而是你打开pages/order_pay/index.js能看到calculateFinalPrice()里嵌套了三层条件判断先扣可用余额再减满减券最后按比例分摊跨店优惠券点开pages/promoter_commission/index.jsgetCommissionList()返回的每条记录都带着status: settled | pending | frozen和对应的时间戳与结算周期标识。它用原生小程序框架没引入任何第三方UI框架比如WeUI或Vant所有样式写在.wxss里所有交互逻辑写在.js里连轮播图都是手撸的swiper组件定时器触摸事件三件套没有黑盒。这意味着你改一行代码立刻知道影响范围在哪——对初学者来说这是比“快速上手”更珍贵的东西可理解性。它适合谁如果你正在写课程设计需要向老师证明你理解了“下单→支付→发货→确认收货→评价”的完整链路而不是只做了个静态商品列表如果你是自学前端的小白想搞懂wx.request怎么配合store.js做全局数据同步onPullDownRefresh如何触发真正的库存刷新或者你是创业者想三天内搭出一个能给投资人演示的分销逻辑原型——这套代码就是为你准备的。它不承诺“拿来就能上线”但承诺“看懂就能复现”。2. 整体架构设计为什么坚持原生开发而非用uni-app或Taro2.1 拒绝“跨端幻觉”回归小程序本质很多人一上来就想用uni-app觉得“一次开发多端运行”很香。但现实是微信小程序的wx.login、wx.getSetting、wx.openSetting、wx.chooseAddress这些API在支付宝或百度小程序里要么不存在要么行为不一致。更关键的是分销海报生成依赖wx.canvasToTempFilePath秒杀倒计时强耦合wx.createSelectorQuery获取节点位置——这些能力在跨端框架里要么阉割要么需要额外适配层。这套代码从第一天就决定死磕原生原因很简单微信小程序的生态壁垒不是技术问题而是商业规则问题。比如“分享到群”触发的shareAppMessage回调里必须解析e.target.dataset.path来携带推广员ID这个路径参数在微信体系里是硬性要求跨端框架根本无法保证其透传可靠性。我们用原生不是守旧而是为了把“微信特有逻辑”全部暴露在明面上——你看pages/promoter_poster/index.js里generatePoster()函数第一行就是const promoterId getApp().globalData.promoterId || wx.getStorageSync(promoter_id)第二行就调用wx.createCanvasContext(posterCanvas)第三行开始逐像素绘制头像、二维码、文案。没有抽象层遮掩错在哪一眼可见。2.2 目录结构即业务地图pages下的每一层都在讲一个故事项目目录不是随意堆砌的pages/下的每个子目录都对应一个独立闭环的业务单元。比如pages/goods_details/不只是商品详情页它内部包含三个关键文件index.js处理规格选择与库存联动spec-selector.js封装了SKU矩阵算法用二维数组映射规格组合与库存evaluate-list.js负责分页加载评价并过滤敏感词。再看pages/order_list/它下面有tab-bar.js管理五种订单状态的切换逻辑order-item.js定义单个订单卡片的渲染规则不同状态显示不同按钮“付款”“查看物流”“申请售后”而order-status-flow.js则用状态机模式固化了订单生命周期created → paid → shipped → confirmed → completed每个状态变更都触发对应的updateOrderStatus()调用。这种分层不是为了好看而是为了降低修改成本。上周有个学生想加“拼团订单”类型他只改了pages/order_list/tab-bar.js里新增一个tab再在order-item.js里补充拼团专属字段渲染其他模块完全不受影响。反观那些把所有页面塞进一个pages/index/目录的项目改个地址管理逻辑得翻遍十几个文件找addressList变量在哪被引用过。2.3 工具层设计util.js、api.js、store.js不是万能胶而是责任明确的齿轮很多新手喜欢把工具函数全塞进util.js结果里面混着日期格式化、字符串截取、网络请求、本地存储操作……最后变成不敢动的“祖传代码”。这套代码的工具层是解耦的util.js只做纯函数formatPrice(9999)返回¥99.99deepClone(obj)深拷贝对象debounce(fn, delay)防抖——没有副作用不操作DOM不发请求api.js是网络层唯一出口所有接口调用都走这里比如api.getOrderList({status: unpaid})内部自动拼接基础URL、添加token、处理401跳转登录页返回Promisestore.js是状态中枢它不存业务数据比如商品列表只存用户会话态userInfo、临时缓存tempCart、全局配置appConfig。关键设计在于store.watch()方法——当你在pages/cart/index.js里执行store.set(tempCart, newCart)所有监听tempCart的页面如首页购物车角标、商品详情页的“加入购物车”按钮状态会自动更新不用手动setData。这三层像齿轮一样咬合pages调用api.js获取数据 →api.js返回后由pages决定存哪里 → 需要共享时存store.js→store.js变化触发视图更新。没有魔法只有清晰的责任划分。3. 核心模块深度拆解从“能用”到“真懂”的五个关键战场3.1 订单全流程状态机不是概念是写死在代码里的if-else链订单状态流转是电商最易出错的环节。这套代码没用复杂的状态机库而是用最直白的switch语句实现但每条分支都附带业务注释。打开pages/order_detail/index.jsonLoad()里调用loadOrderDetail()后核心逻辑在renderOrderStatus()函数renderOrderStatus() { const status this.data.order.status; switch(status) { case created: // 刚创建未支付 this.setData({ actionBtn: { text: 立即付款, type: primary, handler: handlePay }, showLogistics: false }); break; case paid: // 已支付等待发货 this.setData({ actionBtn: { text: 查看物流, type: default, handler: handleTrack }, showLogistics: false // 物流信息尚未录入 }); break; case shipped: // 已发货等待签收 this.setData({ actionBtn: { text: 确认收货, type: primary, handler: handleConfirm }, showLogistics: true // 此时才显示物流轨迹 }); break; case confirmed: // 已签收可评价 this.setData({ actionBtn: { text: 去评价, type: default, handler: handleEvaluate }, showLogistics: true }); break; case completed: // 已完成进入售后期 this.setData({ actionBtn: { text: 申请售后, type: default, handler: handleAfterSale }, showLogistics: true }); break; } }注意两点第一showLogistics的显隐不是凭空判断而是严格绑定状态——发货前不显示物流避免用户困惑第二每个按钮的handler指向具体方法名而不是动态拼接字符串杜绝了“按钮点了没反应”的调试噩梦。实操心得我在教学生时会让他们删掉case shipped分支然后测试“已发货”订单点“确认收货”会发生什么——结果发现按钮消失了但页面没报错。这就是设计的价值状态缺失时界面主动沉默而不是抛出异常让用户崩溃。3.2 优惠券与积分叠加规则不是数学题是业务方拍板的硬约束优惠券和积分的叠加逻辑常被简化为“先减券再扣积分”。但真实场景复杂得多满100减20的店铺券不能和全场通用券同时用积分100抵1元但最高抵扣订单金额的50%新人券仅限首单使用……这套代码把这些规则写死在util.js的calculateDiscount()里// calculateDiscount(orderItems, coupons, userPoints) // 返回 { finalPrice: 128.5, usedCoupons: [couponId], usedPoints: 300 } calculateDiscount(items, coupons, points) { let totalAmount items.reduce((sum, item) sum item.price * item.quantity, 0); let availableCoupons filterValidCoupons(coupons, totalAmount); // 过滤过期、门槛不足的券 // 规则1店铺券优先于平台券 const storeCoupons availableCoupons.filter(c c.scope store); const platformCoupons availableCoupons.filter(c c.scope platform); // 规则2同类型券只用一张 let usedCoupon storeCoupons[0] || platformCoupons[0]; // 规则3积分抵扣上限订单实付金额*0.5 const maxPointDeduction Math.floor((totalAmount - (usedCoupon?.discount || 0)) * 0.5); const usedPoints Math.min(points, maxPointDeduction); return { finalPrice: totalAmount - (usedCoupon?.discount || 0) - (usedPoints / 100), usedCoupons: usedCoupon ? [usedCoupon.id] : [], usedPoints }; }关键细节filterValidCoupons()不仅检查有效期还校验minAmount满减门槛和storeId是否适用于当前商品所属店铺maxPointDeduction的计算基于“实付金额”即扣券后的金额而非原始总价——这点很多学生会忽略导致积分抵扣超限。注意事项测试时务必用真实数据组合比如创建一张“满200减50”的店铺券再加一张“满100减10”的平台券买总价180元的商品观察最终用了哪张券——答案应该是店铺券因为规则明确“店铺券优先”。3.3 分销系统推广关系不是树形结构而是带时间戳的线性链分销模块常被做成无限级代理树但微信小程序实际限制极严分享链接必须带?promoterId123参数且该参数只能由上级推广员生成。这套代码的分销逻辑非常务实推广员入驻pages/promoter_apply/index.js里用户填写姓名、身份证号脱敏存储、收款账户提交后调用api.applyPromoter()后端返回applyId并生成审核状态下级关系pages/promoter_downline/index.js不渲染树状图而是列表展示“直属下级”每条记录包含downlineName、joinTime、totalOrderAmount该下级累计下单金额、commissionRate当前佣金比例海报生成pages/promoter_poster/index.js的核心是drawPoster()它用canvas绘制固定尺寸640x1008px的图片包含顶部品牌Slogan从config.js读取、中间用户头像wx.getUserInfo获取、底部带参数的二维码wx.downloadFile下载后绘制、底部文字“长按识别立享专属优惠”。实操心得海报生成最容易失败的环节是二维码。很多学生用wx.qrcode库但该库依赖canvas上下文而真机调试时wx.createCanvasContext可能因canvas未渲染完成而返回null。解决方案是加一层检测const query wx.createSelectorQuery(); query.select(#posterCanvas).boundingClientRect(); query.exec(rect { if(rect rect[0]) drawOnCanvas(rect[0]); });——先确保canvas节点存在再绘图。3.4 秒杀专区倒计时不是视觉欺骗而是服务端时间锚定秒杀页面pages/rush_buy/index.js的倒计时不是用setInterval简单减秒而是严格同步服务端时间。流程如下页面onLoad()时调用api.getServerTime()获取服务器当前毫秒时间戳计算本地时间与服务端时间的偏移量offset serverTime - Date.now()启动倒计时this.countDownTimer setInterval(() { const now Date.now() offset; /* 用now计算剩余秒数 */ }, 1000)每次倒计时更新都重新调用api.getRushBuyGoods({ timestamp: now })拉取最新库存避免客户端时间不准导致“显示还有库存实际已售罄”。关键参数config.js里定义了rushBuyDuration: 3600秒杀持续1小时rushBuyStartTime: 2024-06-01 10:00:00精确到秒。getRushBuyGoods()接口返回的每个商品都带stock: 0或stock: 5前端只渲染stock 0的商品并禁用“立即抢购”按钮。注意事项真机测试时务必关闭手机自动校准时间手动把手机时间调快1分钟观察倒计时是否依然准确——如果失准说明没走服务端时间同步而是用了本地时间。3.5 购物车与收藏夹本地存储不是终点而是状态同步的起点购物车pages/cart/index.js的数据来源有两处wx.getStorageSync(cart)读取本地缓存api.getCartList()拉取服务端最新数据。但两者不是简单覆盖而是合并策略// 合并逻辑服务端数据为主本地新增商品为辅 mergeCart(localCart, serverCart) { const merged [...serverCart]; localCart.forEach(localItem { const exists serverCart.find(s s.goodsId localItem.goodsId s.specId localItem.specId); if (!exists) { merged.push(localItem); // 本地有、服务端无的商品如未登录时添加 } else { // 服务端有但本地数量不同则以服务端为准防止库存超卖 exists.quantity localItem.quantity; } }); return merged; }收藏夹同理pages/favorite/index.js里onPullDownRefresh()触发api.getFavoriteList()但下拉刷新时会先清空本地favoriteList再用服务端数据填充避免“取消收藏后本地仍显示”。实操心得很多学生把购物车当纯本地功能结果用户换手机登录购物车就空了。这套代码的设计哲学是本地存储只是容灾手段服务端才是唯一真相源。所以每次wx.setStorageSync(cart, cart)前都会先调用api.updateCart(cart)同步到服务端确保两端最终一致。4. 实操部署与调试从开发者工具到真机的完整链路4.1 开发者工具启动三步走绕过90%的环境坑基础配置用微信开发者工具打开项目根目录确保“基础库版本”设置为2.28.0以上因wx.getFileSystemManager在旧版本不可用域名配置在“详情→本地设置”里勾选“不校验合法域名”否则api.js里的https://api.example.com会报SSL错误模拟登录首次运行时app.js的onLaunch()会调用wx.login()但开发者工具无法获取真实code。解决方案在app.js顶部加一段调试代码javascript // 仅调试用上线前删除 if (process.env.NODE_ENV development) { getApp().globalData.userInfo { nickName: 测试用户, avatarUrl: /images/avatar.png }; getApp().globalData.token mock_token_123456; }这样跳过登录流程直接进入首页。提示README.md里写的“无需额外配置即可启动”指的是上述三步是标准流程不是真的零配置。很多学生卡在第一步因为没注意到基础库版本。4.2 真机调试微信扫码的隐藏陷阱与破局方案真机调试最大的坑是“扫码后白屏”。原因通常是网络问题开发者工具的“远程调试”开关未开启或手机与电脑不在同一WiFi下域名未备案api.js里的请求域名如果是个人备案的微信会拦截证书问题HTTPS证书过期或非权威机构签发。破局步骤在开发者工具右上角点击“预览”生成体验版二维码手机微信扫码后若白屏立即下拉触发onPullDownRefresh观察控制台是否有request:fail ssl hand shake error若有说明HTTPS问题临时将api.js里的baseUrl改为http://localhost:3000需后端支持HTTP或更换为已备案的域名若无错误但页面空白检查app.js的onShow()里是否有wx.getSetting权限拒绝逻辑——真机上用户可能拒绝了位置或相册权限导致后续流程中断。注意真机调试时wx.canvasToTempFilePath生成海报的成功率远低于开发者工具。建议在pages/promoter_poster/index.js里加一层重试机制drawPoster().catch(err setTimeout(() drawPoster(), 500));4.3 关键文件作用速查表别再盲目搜索按需定位文件路径核心职责修改风险典型修改场景app.js应用生命周期管理、全局数据初始化⚠️⚠️⚠️ 高添加全局请求拦截、修改登录态存储方式config.jsAPI域名、小程序AppID、业务开关如enableDistribution: true⚠️ 中切换测试/生产环境、启用或禁用分销模块store.js全局状态管理、watch监听机制⚠️⚠️ 中高新增需要跨页面共享的状态如购物车数量角标util.js纯工具函数无副作用✅ 低增加新的格式化方法如手机号脱敏maskPhone(13812345678)api.js所有网络请求封装⚠️⚠️ 中高新增接口如api.getBannerList()、修改请求头pages/user_center/index.js个人中心首页路由入口⚠️ 低调整菜单顺序、隐藏某个入口如禁用“余额查询”实操心得我让学生改需求时第一件事是查这张表。比如“增加消息通知入口”先看pages/user_center/index.js里有没有预留slot没有就加再看store.js里是否需要新增notificationCount状态最后确认api.js里是否有getNotificationList()接口——而不是一上来就改app.js避免牵一发而动全身。5. 常见问题与排查技巧实录那些文档里不会写的血泪教训5.1 “页面空白”问题排查树从现象到根因的决策路径当页面打开一片空白不要急着重装开发者工具按以下顺序排查看控制台开发者工具Console里是否有ReferenceError: xxx is not defined如果有说明xxx变量在data里未声明或setData时拼写错误如this.setData({ userInof: {} })少了个r查WXML打开WXML面板看是否渲染了view wx:if{{!loaded}}加载中.../view但loaded始终为false——检查onLoad()里是否漏写了this.setData({ loaded: true })验API在api.js里console.log(request url:, url)确认请求URL是否正确常见错误/api/goods/list写成/api/goods/list/多了一个斜杠测数据在pages/goods_list/index.js里console.log(goods data:, this.data.goodsList)如果为空说明api.getGoodsList()没返回数据或返回格式不符如后端返回{ code: 0, data: [...] }但前端期望{ list: [...] }审权限真机上白屏检查wx.getSetting返回的authSetting里scope.userInfo是否为false若是则getUserInfo按钮点击无效需引导用户手动开启。经验80%的“空白页”问题出在第2步和第4步。学生常犯的错误是WXML里写text{{goods.name}}/text但goods是数组应该用wx:for循环或者API返回{ result: [...] }但代码里写res.data.list导致list为undefined。5.2 “倒计时错乱”终极解决方案服务端时间锚定的三重校验秒杀倒计时不准根源在于客户端时间不可信。我们的解决方案是三重校验首次校准onLoad()时调用api.getServerTime()计算偏移量offset定时校准每5分钟再次调用api.getServerTime()更新offset避免长时间运行后偏移累积临界校验倒计时剩余10秒时强制调用api.getRushBuyStatus()确认活动是否真的开始——如果服务端返回status: not_started立即停止倒计时并提示“活动尚未开始”。代码片段startCountDown() { this.getServerTimeOffset(); this.countDownTimer setInterval(() { const now Date.now() this.data.offset; const remaining this.data.startTime - now; if (remaining 0) { this.stopCountDown(); this.setData({ countdown: 00:00:00 }); // 临界校验 if (this.data.remainingSeconds 10000) { api.getRushBuyStatus().then(res { if (res.status ! started) { wx.showToast({ title: 活动尚未开始, icon: none }); } }); } return; } this.setData({ countdown: this.formatTime(remaining) }); }, 1000); }5.3 “优惠券不生效”避坑指南四个必查维度学生反馈“领了券但结算时不减钱”90%的情况源于以下四点时间维度检查coupon.validFrom和coupon.validTo确保当前时间在有效期内注意时区后端返回的时间戳需转为本地时间比较门槛维度coupon.minAmount是否小于等于订单总金额注意minAmount是“满多少减”不是“减多少满多少”范围维度coupon.scope是all还是store如果是store检查商品storeId是否匹配叠加维度coupon.canCombine字段是否为true若为false则该券不能与其他券同时使用。排查技巧在pages/order_pay/index.js的calculateFinalPrice()里加一行console.log(available coupons:, availableCoupons)眼见为实。5.4 “分销海报生成失败”高频原因与修复清单现象可能原因修复方案canvas空白wx.createCanvasContext(posterCanvas)返回null确保WXML中canvas idposterCanvas /已渲染用wx.createSelectorQuery()延迟获取二维码不显示wx.downloadFile下载失败检查二维码URL是否可访问在浏览器打开测试或改用wx.previewImage临时替代文字模糊canvas宽高未设为物理像素WXML中canvas idposterCanvas width640 height1008 /JS中ctx.scale(2, 2)适配高清屏头像拉伸ctx.drawImage()参数错误正确写法ctx.drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight)注意源区域和目标区域比例实操心得海报生成失败时先在开发者工具里打印ctx对象确认是否为CanvasContext实例再打印image对象确认是否为合法图片路径。别猜要亲眼看到。5.5 “真机调试无响应”急救包五招快速恢复当手机扫码后页面无反应按顺序执行重启开发者工具关闭所有窗口重新打开项目清除缓存开发者工具菜单栏→“编译”→“清除缓存并重新编译”重置手机微信手机微信→我→设置→通用→存储空间→清理缓存注意不删聊天记录换WiFi网络确保手机和电脑在同一局域网关闭手机流量降级基础库在开发者工具“详情→本地设置”里将基础库版本改为2.25.2兼容性更强。最后一招如果以上全无效新建一个空白小程序项目把本项目的pages/和utils/目录复制过去重新配置app.json——往往是项目配置文件损坏。6. 学习路径建议如何用这套代码真正提升工程能力这套代码的价值不在于让你复制粘贴上线而在于提供一个“可拆解、可验证、可质疑”的学习样本。我的建议是分三阶段吃透它第一阶段单点突破1-2周选一个你最感兴趣的模块比如“订单状态流转”。目标不是看懂所有代码而是能独立修改把“待发货”状态改成“已打包”并在对应页面显示新按钮。过程中你会被迫理解order.js的API结构、store.js的状态更新机制、WXML的条件渲染语法。这个阶段的关键是“动手改”哪怕改错了也要看报错信息查文档直到跑通。第二阶段横向对比2-3周挑两个关联模块比如“购物车”和“订单结算”。对比它们的数据流向购物车数据如何传递给订单页pages/cart/index.js里的wx.navigateTo({ url: /pages/order_pay/index?cartIds... })和pages/order_pay/index.js里的onLoad(options)如何解析参数你会发现看似独立的页面其实是通过URL参数、全局store、事件总线wx.$emit三种方式耦合的。这个阶段的目标是画出数据流图标注每个环节的输入输出。第三阶段纵向深挖3-4周选一个技术点深挖比如“canvas海报生成”。不仅要会用还要理解为什么用wx.createCanvasContext而不是canvas标签的bindtouchstartctx.draw()和wx.canvasToTempFilePath()的执行顺序为何不能颠倒尝试自己写一个简易的二维码生成器用qrcode.js库替换掉原生绘制逻辑。这个阶段的目标是“造轮子”在理解的基础上重构一个子模块。最后分享一个小技巧我在带学生时会让每个人给util.js里的每个函数写单元测试用jest-mini-program比如test(formatPrice should return ¥99.99 for 9999, () { expect(formatPrice(9999)).toBe(¥99.99); });。测试写完函数逻辑自然就刻进脑子里了。这套代码不是终点而是你前端工程能力跃迁的起跳板——跳得够高才能看清整个小程序生态的轮廓。本文还有配套的精品资源点击获取简介这套微信小程序商城前端代码覆盖电商核心业务场景首页支持轮播与推荐位分类页按层级展示商品类目商品详情页集成规格选择、图文介绍与评价模块购物车支持多商品编辑与结算跳转订单管理包含待付款、待发货、待收货、已完成及售后全状态个人中心整合地址管理、会员信息、积分明细、优惠券领取与核销、余额查询分销功能提供推广员入驻、下级关系树、佣金记录与分享海报生成秒杀专区独立入口倒计时与库存同步控制另含搜索页、收藏夹、活动页、商品评价等高频页面。所有页面基于原生小程序框架开发使用JavaScript编写目录结构清晰如pages/goods_details、pages/order_list、pages/user_coupon等关键逻辑封装在util.js、api.js、store.js等工具文件中配套README.md说明启动方式支持开发者工具预览和真机调试开箱即用适合教学演示、课程设计或原型验证不适用于正式上线生产环境。本文还有配套的精品资源点击获取