微信电商小程序完整项目源码解析:从购物车到支付全链路
简介这套项目源码包是一份完整的微信小程序电商毕业设计/期末大作业面向计算机专业学生、小程序开发入门者以及需要快速交付课设项目的人群。压缩包共91个文件包含12组WXML/WXSS/JS/JSON页面代码、12个WXSS样式文件、14个JavaScript逻辑文件、24张PNG配图资源另附README开发说明、docx/doc图文导入教程和mp4导入操作录屏整包大小约33.56MB。项目覆盖商品列表、商品详情、购物车、个人中心、订单管理等电商核心模块代码中涉及组件化开发、数据绑定与setData刷新、wx.request网络请求、用户登录授权、微信支付、分包加载与页面路由配置等关键技术。已有1228人进行学习浏览配套文档与视频展示了从源码导入到运行调试的完整过程便于读者对照理解每个页面的实现思路同时可作为毕业设计答辩或课程期末作业的参考项目。1. 一套能跑通的微信电商小程序比你想的更值得拆微信小程序开发入门不难难的是把页面、数据、支付、分包这些环节串成一个完整系统。这份微信电商小程序源码恰好是一份完整的电商项目不是那种只搭了个首页框架的demo而是带购物车、商品列表、订单流程、用户授权和支付逻辑的全链路实现适合做毕业设计、期末大作业也适合想在小程序里快速搭电商闭环的开发者直接改造成自己的项目。压缩包里除了源码还附带了图文导入文档和视频教程对第一次接触小程序环境搭建的人来说非常友好。整个项目基于微信原生框架没有引入第三方UI库主要靠WXML、WXSS、JavaScript和JSON四件套完成界面与逻辑这类写法能最大程度暴露小程序运行机制的细节读完这套代码再去用uni-app或Taro写跨端应用会顺手得多。2. 从目录结构看工程组织小程序电商项目的骨架设计2.1 app.json、app.js、app.wxss全局配置如何撑起整个应用打开项目先看根目录的app.json这是小程序运行时的总配置文件所有页面的注册、窗口外观、tabBar导航和网络超时时间都在这一个文件里定义。常见的错误做法是把页面全部塞进pages数组但电商项目里商品详情、订单确认、支付结果这类页面只在特定流程出现放主包会让启动加载变慢。合理的方式是主包只放首页、分类、购物车、个人中心这些核心Tab页其余页面放进分包。app.js是全局逻辑入口项目里在这做了两层初始化工作第一层通过wx.getStorageSync读取本地缓存的登录态和购物车数据第二层在onLaunch里调用登录接口拉取用户openid。很多初学者会把所有页面都要用的方法复制到各个Page里这个项目用globalData挂载全局变量和公共方法购物车数量、用户信息、系统状态这类跨页面共享的数据放在这里避免每个页面重复请求。页面的公共样式放在app.wxss里项目把按钮重置、价格文本统一格式、商品卡片阴影这些高频样式抽成了公共类。电商页面视觉密度高如果每个wxss都重复写一遍这些样式改主题色会非常痛苦全局样式类能保证主要页面的显示一致性。2.2 页面四件套WXML/WXSS/JS/JSON的职责分工pages目录下每个页面文件夹都包含四个文件调试时可以只看这一组文件WXML负责结构布局可以把它当成一个增强版的HTML支持wx:if和wx:for这类逻辑指令WXSS负责样式支持rpx响应式单位iPhone和Android屏幕都能自动适配JS是页面逻辑和数据处理的核心JSON则单独配置当前页面的导航栏标题、背景色、下拉刷新开关等窗口行为。商品列表页的WXML里可以看到wx:for被用来渲染商品数据每一项绑定data-id属性点击时通过dataset取值跳转详情页。WXSS部分大量使用flex布局实现两列商品瀑布流用rpx而不是px做单位能保证750设计稿在不同宽度的屏幕上等比缩放。JS文件里定义了onLoad加载数据、onReachBottom触底加载下一页、onPullDownRefresh下拉刷新这些生命周期函数这是电商列表页的核心交互。页面JSON里只写页面级别的窗口配置不会覆盖app.json中的全局设置。2.2.1 模板与组件template目录在电商项目里的复用方式项目的template目录存放公共模板和自定义组件不同模板只渲染结构没有独立逻辑。商品卡片是最典型的模板使用场景首页、搜索页、推荐位都要展示类似的商品信息把商品图、标题、价格封装成模板通过import引入并在对应位置传参避免多处重复写相同的WXML片段。template nameproduct-card view classproduct-item bindtapgoDetail>goDetail(e) { const { id } e.currentTarget.dataset; wx.navigateTo({ url: /pages/goods/detail?goodsId${id} }); }详情页在onLoad生命周期接收goodsId参数用它去请求详情接口再把返回的数据setData到页面上。电商详情页一般包含商品主图、价格、规格选择、用户评价、底部操作栏、商品详情图文几个区块每个区块单独用一个view包裹配合wx:if按需渲染数据未返回时不会出现空白或错版。详情页的数据绑定使用双大括号语法无论是文本节点的{{goods.title}}还是属性节点的src{{goods.cover}}渲染机制都是相同的。表达式中支持三元运算和简单字符串拼接比如{{goods.stock 0 ? 有货 : 缺货}}或{{销量 goods.sales}}但不要把复杂函数调用放进模板维护成本高这部分的计算应该在JS里先处理成展示字段再绑定。4. 购物车状态管理与网络请求小程序开发中真正的核心难点4.1 购物车数据的本地持久化与页面间同步购物车是电商项目里最复杂的模块之一因为它的状态需要多个页面共享商品详情页能直接加购购物车Tab页能修改数量和删除商品结算页依赖购物车数据计算总价。项目采用app.js里的globalData配合wx.setStorageSync实现购物车状态管理每次加购或修改数量后先更新globalData中的购物车数组再同步写入本地storage这样应用冷启动后也能恢复购物车数据。商品详情页加购时向购物车数组追加一条记录如果同一商品已存在则增加数量。购物车Tab页的每条商品记录包含goodsId、title、price、cover、count和checked六个字段checked字段控制是否参与结算。addToCart() { const item { goodsId: this.data.goods.id, title: this.data.goods.title, price: this.data.goods.price, cover: this.data.goods.cover, count: 1, checked: true }; let cart wx.getStorageSync(cart) || []; const existing cart.find(g g.goodsId item.goodsId); if (existing) { existing.count 1; } else { cart.push(item); } wx.setStorageSync(cart, cart); this.setData({ cartCount: cart.reduce((sum, g) sum g.count, 0) }); }购物车加减操作先找到商品在数组中的索引再修改对应元素的count值。计算总价时用reduce遍历购物车数组只累加checked为true的商品。这里有一个典型的setData性能误区修改深层数据时如果直接setData整个cart数组当购物车里商品很多时会造成不必要的渲染开销。推荐的写法是使用数据路径更新比如this.setData({cart[0].count: 3})让小程序只更新指定路径的视图。删除商品走filter方法返回过滤后的新数组再setData。注意所有修改都得是纯操作不要直接修改原有的cart变量然后setData同一个引用新数组才会触发视图层的有效对比。4.2 wx.request封装与请求拦截统一处理登录态过期微信小程序的网络请求使用wx.request发起它是基于Promise封装的异步接口但在项目实际开发中直接在每个页面写wx.request会带来两个问题一是代码重复严重二是无法统一处理token过期、接口报错、loading展示这些通用逻辑。utils目录里的request.js做了这层封装把基础配置抽成常量通过返回Promise让页面可以用async/await拉平回调嵌套。const request (url, method, data) { return new Promise((resolve, reject) { wx.request({ url: apiBaseUrl url, method: method, data: data, header: { Content-Type: application/json, Authorization: wx.getStorageSync(token) || }, success: (res) { if (res.statusCode 200) { resolve(res.data); } else if (res.statusCode 401) { wx.removeStorageSync(token); wx.navigateTo({ url: /pages/login/index }); reject(new Error(登录已过期)); } else { reject(new Error(res.data.message || 请求失败)); } }, fail: (err) reject(err) }); }); };wx.request的封装逻辑有几个值得复用的细节header里从storage读取token并放到Authorization字段符合JWT鉴权的通行做法statusCode为401时自动清token并跳转登录页不用每个页面单独判断fail分支统一定义错误提示。如果需要带loading效果可以在请求前调用wx.showLoading并在complete回调里wx.hideLoading但要注意多个并发请求时loading会被提前关闭。项目的商品列表、搜索、订单查询都通过这个封装调用后端接口参数里除了业务参数外还包含page和pageSize做分页。触底加载时页码自增每次请求追加到goodsList数组后setData同时记录loading状态防止onReachBottom在请求未结束时重复触发。4.3 用户登录授权wx.login与wx.getUserInfo的配合方式用户体系是小程序电商的基础设施。项目使用wx.login获取临时code将code发送到后端换取openid和session_key后端返回自定义登录态token前端将token存入storage。后续每次wx.request都携带token后端校验通过后返回用户数据。页面需要展示头像和昵称时调用wx.getUserInfo会触发授权弹窗。团队开发时常见的做法是把授权入口放在个人中心页用户主动点击才弹窗而不是页面加载时强制弹屏这样不会因为用户拒绝授权导致整个页面不可用。拿到用户信息先存globalData供全局使用再调接口更新服务端的用户资料。需要特别注意的是wx.getUserInfo在新版本基础库中已不能直接弹出授权框只能获取匿名信息。现在标准做法是使用button组件的open-typechooseAvatar获取头像配合input typenickname获取昵称。老项目如果发现授权弹窗不出现多半是基础库版本升级导致API行为变更查看此问题优先确认调试的基础库版本。5. 微信支付、分享与分包加载上线电商小程序前的最后一道关5.1 支付流程的前后端配合关键在签名页面只是发起方电商系统的核心交易环节是微信支付小程序的支付链路和H5支付完全不同必须走标准的统一下单流程。用户在结算页确认订单后前端把商品id、数量、收货地址等数据提交到后端后端在微信支付服务端生成预支付单返回一组支付参数timeStamp、nonceStr、package、signType、paySign。前端拿到参数后调用wx.requestPayment微信SDK校验签名通过后拉起收银台。wx.requestPayment({ timeStamp: res.timeStamp, nonceStr: res.nonceStr, package: res.packageValue, signType: RSA, paySign: res.paySign, success: (payResult) { wx.navigateTo({ url: /pages/order/success }); }, fail: (err) { wx.showToast({ title: 支付未完成, icon: none }); } });支付逻辑的代码本身非常简洁难点全在后端。支付参数必须由后端通过API证书签名后生成前端直接用后端返回的数据发起请求任何前端自签名的做法都无法通过验证。开发调试时需要在微信商户平台配置支付回调域名并在小程序后台request合法域名里加入对应接口域名否则真机调试会直接请求失败。5.2 分享与转发onShareAppMessage把商品传播出去电商小程序天然依赖社交裂变微信小程序的分享机制通过Page的onShareAppMessage生命周期实现。页面开启分享后用户点右上角菜单即可转发给好友或群聊。可以在onShareAppMessage中自定义转发的标题、图片和路径分享路径携带商品id或推荐人信息新用户通过该路径打开小程序时就能定位到对应页面。onShareAppMessage() { const goods this.data.goods; return { title: ${goods.title}仅需¥${goods.price}, path: /pages/goods/detail?goodsId${goods.goodsId}inviter${this.data.userId}, imageUrl: goods.cover }; }小程序分享的imageUrl参数如果不传默认截取当前页面顶部作为分享图但截图效果不稳定电商场景下最好单独准备一张底图图上标注商品名和促销信息让群聊中的分享链接更容易被点击。想要监听用户是否分享成功或失败可以给onShareAppMessage的返回值配置success和fail回调但转发结果只能在部分基础库版本中拿到生产环境建议仅做打点统计不要依赖回调做核心业务判断。5.3 分包加载把商品详情页从主包里拆出去小程序主包体积上限是2MB超过后无法上传发布把所有代码塞在主包里很快就会遇到这个瓶颈。项目里把商品详情、订单列表、用户中心这些独立页面拆到子包中app.json配置subPackages字段字段内每个包的root参数指定分包目录pages参数列出该分包的页面路径。{ pages: [ pages/index/index, pages/category/index, pages/cart/index, pages/user/index ], subPackages: [ { root: packageGoods, pages: [ pages/goods/detail, pages/goods/review, pages/order/confirm ] }, { root: packageUser, pages: [ pages/order/list, pages/order/detail, pages/address/edit ] } ] }通过分包配置的结果是用户打开小程序只需要下载主包的四个Tab页从列表页跳转到商品详情时才会下载packageGoods这个分包。分包并不是越小越好控制粒度需要考虑页面跳转的关联性商品详情和订单确认往往在同一个浏览路径上拆在同一个包里能减少一次下载等待。独立分包的页面跳转路径要在url中带上root前缀从主包跳分包和分包间跳转的规则并不相同。调试分包时打开开发工具的详细信息面板可以看到当前页面所在包的大小和加载耗时如果发现某个子包体积依然超标需要在包内进一步做组件按需加载或图片压缩。优化顺序上先压缩体积最大的商品图电商项目的性能瓶颈大多来自图片资源几个全宽商品大图就能占掉几百KB首屏上轮播图和推荐位优先使用压缩尺寸的图片点击查看原图再加载高清资源。5.4 图片资源性能优化电商小程序首屏加载的流量与速度权衡电商页面图片密度高同样的CSS代码在Wi-Fi和4G弱网环境下的加载体验差距巨大。项目里使用image组件时加lazy-load属性让屏幕外的图片在滚动到可视区域附近时才加载。图片本身的体积控制在80KB以内采用商户后台压缩到704像素宽的上传版本覆盖大部分手机屏幕的2倍分辨率。另一个容易忽略的性能点是长列表页的分页加载策略。onReachBottom触发下一页请求与两边参数page、pageSize之间的关系必须保持一致首次加载成功后更新page并存储在data中下次触底基于当前page自增后再请求避免page在请求失败后仍自增导致数据缺页。经验不足的开发经常在page的初始值和请求完成的回调里都做了自增实际请求页码翻倍。使用Charles或微信开发者工具自带的Network面板可以检查请求的参数和响应结果分页错位的现象在弱网环境下更容易复现。本文还有配套的精品资源点击获取