简介:这是一套开箱即用的球鞋垂直电商类微信小程序源码,面向前端初学者与小程序开发者,助力快速掌握商城类应用的核心开发流程与工程实践。资源包含260个文件,涵盖59个JS逻辑文件(如index.js、submitOrder.js)、53个WXML结构模板、53个JSON配置文件(含app.json、页面级json)、53个WXSS样式文件及42个图片资源(png/jpg),整体压缩包仅2.72MB,轻量易读。已有322人学习下载,适合通过真实业务场景理解小程序生命周期(onLaunch/onShow)、TabBar导航配置、页面模块化设计(首页/详情页/购物车/订单页)及utils工具函数复用机制。源码结构规范,pages目录功能划分清晰,配套kefu.jpg、case.jpg等运营素材与showdown.js、html2json.js等实用工具,可直接调试运行,是学习商品展示、购物车管理、订单提交与支付集成全流程的理想范例。
1. 球鞋商城微信小程序源码不是“开箱即用”的成品,而是可深度定制的业务骨架
你下载的球鞋商城微信小程序源码.rar,表面看是一堆.js、.wxml、.wxss文件,但实际它是一套面向垂直品类(球鞋)的、已跑通核心链路的工程化起点。它不包含后台服务、数据库或支付通道的完整部署包,也不预装品牌Logo、SKU图库或库存系统——这意味着它既不是“拿来就能卖鞋”的SaaS工具,也不是仅供学习的Demo。它的价值在于:已实现商品列表瀑布流渲染、购物车状态持久化、收藏夹双向同步、订单提交与状态跳转、客服入口集成等6类高频交互模块,且所有页面均通过wx:for+wx:key实现高性能列表复用,setData调用频次经实测控制在单次操作≤3次。适合有前端基础、需快速验证球鞋垂直电商MVP的开发者,或正在带教小程序实战课的讲师——你得自己补全云函数鉴权逻辑、替换showdown.js中的Markdown解析规则以适配球鞋参数表,还要重写submitOrder.js里的地址校验正则来匹配国内快递网点编码格式。
2. 源码结构解析:从app.js全局生命周期到pages/页面级数据流闭环
2.1app.js:全局状态管理与路由拦截的底层锚点
小程序启动时,app.js的onLaunch会触发wx.getSystemInfoSync()获取设备信息,并将windowWidth和pixelRatio存入globalData。但真正关键的是onShow中的登录态校验逻辑:
onShow: function () { const token = wx.getStorageSync('user_token'); if (!token) { wx.navigateTo({ url: '/pages/login/login' }); } else { // 启动时刷新用户信息缓存 this.globalData.userInfo = wx.getStorageSync('user_info') || {}; } }注意:此处未调用
wx.login()重新获取 code,说明该源码默认采用「静默登录」策略——依赖用户已授权且 token 未过期。若你的业务要求强制刷新登录态,需在onShow内增加wx.checkSession()判断,并在失败时跳转登录页。
app.js还定义了globalData中的cartList数组,其初始值为空数组[]。但购物车数据实际由buyCarList.js维护,app.js仅作为跨页面共享的引用容器。这种设计避免了每个页面重复请求购物车接口,但要求所有修改必须通过app.globalData.cartList = newCartList同步,否则index.js和cart.js会出现状态不一致。
2.2app.json:TabBar 配置与页面路径映射的硬性约束
app.json中的"tabBar"配置直接决定用户可见的底部导航栏:
"tabBar": { "color": "#7A7E83", "selectedColor": "#3cc51f", "borderStyle": "black", "backgroundColor": "#ffffff", "list": [ { "pagePath": "pages/index/index", "text": "首页", "iconPath": "assets/images/tabbar/home.png", "selectedIconPath": "assets/images/tabbar/home-active.png" }, { "pagePath": "pages/collection/collection", "text": "收藏", "iconPath": "assets/images/tabbar/fav.png", "selectedIconPath": "assets/images/tabbar/fav-active.png" } ] }提示:
pagePath必须与pages/目录下的真实路径严格一致,且不能包含.js或.wxml后缀。若你新增pages/order/order页面,必须在此处追加 list 项,否则wx.switchTab()调用会失败并报错page not found。
app.json的"sitemapLocation"字段被设为"sitemap.json",这是微信搜索收录的必要配置。若你删除该文件或修改路径,小程序将无法被微信内搜索抓取——这对球鞋类目尤其重要,因为用户常通过“AJ1”“椰子350”等关键词直接搜索商品。
2.3pages/目录:页面级 MVVM 模式与 WXML 渲染性能关键点
每个页面目录(如pages/index/)包含四类文件,其协同关系如下:
| 文件类型 | 作用 | 球鞋场景特例 |
|---|---|---|
index.wxml | 结构模板,使用<view><image><text>构建UI | 商品卡片中<image src="{{item.cover}}" mode="aspectFill">使用aspectFill保证球鞋主图不拉伸变形 |
index.js | 逻辑层,处理onLoad、onPullDownRefresh等生命周期 | onLoad中调用getShoeList({ category: 'air-jordan' })加载AJ系列专属列表 |
index.wxss | 样式层,支持 rpx 单位适配不同屏幕 | .shoe-card { width: 345rpx; margin: 0 12rpx; }确保在 iPhone 14 Pro Max 上单行显示2个球鞋卡片 |
index.json | 页面配置,覆盖app.json全局设置 | "navigationBarTitleText": "Air Jordan 专区"动态设置导航栏标题 |
index.js的onLoad函数中,this.setData({ shoeList: res.data })是核心操作。但需注意:res.data是后端返回的原始数组,而shoeList在data: {}中已声明为[]。若后端返回空数组,setData仍会触发 WXML 重渲染,导致空白页闪烁。优化方案是在setData前加判断:
if (res.data && res.data.length > 0) { this.setData({ shoeList: res.data }); } else { this.setData({ shoeList: [], emptyTip: '暂无该系列球鞋' }); }这样既避免无效渲染,又提供用户友好的空状态提示。
2.4utils/工具库:html2json.js与球鞋富文本解析的适配改造
utils/html2json.js是将 HTML 字符串转为 JSON 树结构的工具,原生用于解析商品详情页中的<p><strong>经典款</strong></p>等标签。但在球鞋场景中,详情页常含<table>描述尺码对照表、<img>展示多角度实拍图。原版html2json.js对<table>支持较弱,会丢失colspan属性。
改造步骤:
- 找到
html2json.js中parseTag函数内的switch(tag)分支; - 为
table标签添加新分支:
case 'table': node.attrs = { ...node.attrs, border: attrs.border || '0' }; break;- 在
parseAttr函数中补充colspan解析:
if (name === 'colspan') { attrs.colspan = value; }改造后,球鞋详情页中的<table><tr><td colspan="2">US 9 / EU 42.5</td></tr></table>可正确转为带colspan字段的 JSON 节点,WXML 中可通过{{item.attrs.colspan}}动态设置<view>的style属性实现跨列布局。
3. 核心业务模块实战:购物车状态同步、订单提交与客服入口集成
3.1 购物车数据持久化与跨页面同步机制
购物车功能由buyCarList.js独立维护,其核心是saveToStorage方法:
saveToStorage: function(cartList) { try { wx.setStorageSync('cart_list', cartList); // 同时更新 app.globalData getApp().globalData.cartList = cartList; } catch (e) { console.error('购物车存储失败', e); } }该方法在用户点击「加入购物车」按钮后被调用。但关键细节在于:cartList是一个对象数组,每个对象含id、title、price、count、selected字段。其中selected为布尔值,控制该商品是否参与结算。
注意:
wx.setStorageSync的存储上限为 10MB,但单个 key 不超过 1MB。若球鞋商城SKU超5000款,且每条记录含图片base64,需改用云开发数据库存储购物车,而非本地缓存。
pages/cart/cart.js在onShow中读取数据:
onShow: function() { const cartList = wx.getStorageSync('cart_list') || []; this.setData({ cartList: cartList }); }但此处存在竞态风险:若用户在index页面添加商品后未触发cart页面onShow(例如直接下拉刷新),cart页面可能显示旧数据。解决方案是在app.js的onShow中广播事件:
// app.js onShow: function() { // ...原有逻辑 const eventChannel = this.getOpenerEventChannel(); if (eventChannel) { eventChannel.emit('cartUpdated'); } }然后在cart.js的onLoad中监听:
onLoad: function() { this.getOpenerEventChannel().on('cartUpdated', () => { this.setData({ cartList: wx.getStorageSync('cart_list') || [] }); }); }这样确保任何页面触发购物车变更后,cart页面都能实时响应。
3.2 订单提交流程:submitOrder.js中的地址校验与支付跳转
submitOrder.js的formSubmit事件处理器负责生成订单:
formSubmit: function(e) { const formData = e.detail.value; // 校验收货地址 if (!/^\d{6}$/.test(formData.postcode)) { wx.showToast({ title: '邮编格式错误', icon: 'none' }); return; } // 构造订单数据 const orderData = { items: getApp().globalData.cartList.filter(i => i.selected), address: formData.address, phone: formData.phone, postcode: formData.postcode }; // 调用云函数创建订单 wx.cloud.callFunction({ name: 'createOrder', data: orderData, success: res => { wx.navigateTo({ url: `/pages/orderDetail/orderDetail?orderId=${res.result.orderId}` }); } }); }提示:此处
formData.postcode的正则/^\d{6}$/仅适配中国邮政编码。若需支持国际订单,应改为formData.country === 'CN' ? /^\d{6}$/ : /^[A-Za-z0-9\s-]{3,10}$/,并在 WXML 中动态显示国家选择器。
订单详情页orderDetail.js通过onLoad获取orderId参数:
onLoad: function(options) { this.setData({ orderId: options.orderId }); this.getOrderDetail(options.orderId); }但options.orderId来自 URL 查询参数,若用户手动修改 URL 中的 ID,可能看到他人订单。安全加固方式是在getOrderDetail中增加权限校验:
getOrderDetail: function(orderId) { wx.cloud.callFunction({ name: 'getOrderById', data: { orderId: orderId, userId: getApp().globalData.userId } }).then(res => { if (res.result.order.userId !== getApp().globalData.userId) { wx.showToast({ title: '无权查看此订单', icon: 'none' }); wx.navigateBack(); } else { this.setData({ order: res.result.order }); } }); }3.3 客服入口集成:kefu.jpg与case.jpg的静态资源加载策略
pages/index/index.wxml中客服按钮代码为:
<view class="kefu-btn" bindtap="openKefu"> <image src="/assets/images/kefu.jpg" mode="aspectFit"></image> </view>kefu.jpg是客服图标,case.jpg是案例展示图。二者均存于assets/images/目录,但源码未启用wx.preloadImage预加载。当用户首次进入首页时,kefu.jpg会触发网络请求,若图片体积超100KB,在2G网络下可能延迟1秒以上才显示。
优化方案:
- 将
kefu.jpg压缩至 12KB 以内(使用 TinyPNG 工具); - 在
app.js的onLaunch中预加载:
wx.preloadImage({ urls: ['/assets/images/kefu.jpg', '/assets/images/case.jpg'], success: () => console.log('客服图预加载完成'), fail: err => console.warn('预加载失败', err) });预加载后,<image>标签渲染时将直接从内存读取,消除白屏等待。
4. 球鞋品类专项优化:商品图懒加载、尺码选择器与 Markdown 参数表渲染
4.1 商品列表图片懒加载:lazyLoad与IntersectionObserver的兼容性落地
球鞋商品图通常尺寸较大(800×800px),首页瀑布流若一次性加载20张,首屏资源超2MB。源码中index.wxml使用传统src加载:
<image src="{{item.cover}}" mode="aspectFill" class="shoe-img"></image>这会导致滚动卡顿。微信小程序 2.27.0+ 支持lazy-load属性,但需配合IntersectionObserver实现精准控制:
<image lazy-load src="{{item.cover}}" mode="aspectFill" class="shoe-img" bindload="onImageLoad" >onImageLoad: function(e) { const index = e.currentTarget.dataset.index; const loadedImages = this.data.loadedImages || []; loadedImages[index] = true; this.setData({ loadedImages: loadedImages }); }, onReachBottom: function() { // 底部触达时加载下一页 this.loadMoreShoes(); }注意:
lazy-load属性仅对mode="widthFix"有效,而球鞋图需mode="aspectFill"保持比例。因此必须降级使用IntersectionObserver:
// index.js onLoad 中初始化 this.createIntersectionObserver() .relativeToViewport({ bottom: 200 }) .observe('.shoe-img', (res) => { if (res.intersectionRatio > 0) { const dataset = res.target.dataset; this.setData({ [`shoeList[${dataset.index}].loaded`]: true }); } });WXML 中对应修改:
<image src="{{item.loaded ? item.cover : '/assets/images/placeholder.png'}}" mode="aspectFill" class="shoe-img" >chooseSize: function(e) { const sizeMap = { 'US': { '9': 'EU42.5', '9.5': 'EU43', '10': 'EU43.5' }, 'EU': { '42.5': 'US9', '43': 'US9.5', '43.5': 'US10' } }; const selectedSize = e.detail.value; const currentSystem = this.data.sizeSystem; const converted = sizeMap[currentSystem][selectedSize] || ''; this.setData({ selectedSize: selectedSize, convertedSize: converted }); }WXML 中绑定:
<picker bindchange="chooseSize" range="{{sizeOptions}}"> <view class="picker">{{selectedSize || '请选择尺码'}}</view> </picker> <view class="size-convert">换算:{{convertedSize}}</view>但源码未提供sizeOptions初始化。需在onLoad中根据商品属性动态生成:
onLoad: function(options) { const shoe = this.data.shoe; let sizeOptions = []; if (shoe.sizeSystem === 'US') { sizeOptions = ['7', '7.5', '8', '8.5', '9', '9.5', '10', '10.5', '11']; } else if (shoe.sizeSystem === 'EU') { sizeOptions = ['39', '39.5', '40', '40.5', '41', '41.5', '42', '42.5', '43']; } this.setData({ sizeOptions: sizeOptions }); }这样确保 AJ1 页面显示 US 尺码,Yeezy 页面显示 EU 尺码,符合球鞋用户认知习惯。
4.3 Markdown 参数表渲染:showdown.js的球鞋字段增强
球鞋详情页常含参数表格(如「鞋面材质:Flyknit」「中底科技:Zoom Air」),源码用showdown.js解析 Markdown。但原版不支持表格内嵌 HTML,需扩展:
// utils/showdown.js 修改 parseTable 函数 const tableRegex = /<table[^>]*>([\s\S]*?)<\/table>/gi; html = html.replace(tableRegex, (match, content) => { // 提取每一行 const rows = content.match(/<tr[^>]*>([\s\S]*?)<\/tr>/gi) || []; let tableHtml = '<view class="shoe-table">'; rows.forEach(row => { const cells = row.match(/<td[^>]*>([\s\S]*?)<\/td>/gi) || []; tableHtml += '<view class="shoe-row">'; cells.forEach(cell => { const text = cell.replace(/<td[^>]*>|<\/td>/g, '').trim(); tableHtml += `<view class="shoe-cell">${text}</view>`; }); tableHtml += '</view>'; }); tableHtml += '</view>'; return tableHtml; });WXML 中添加样式:
.shoe-table { display: table; width: 100%; } .shoe-row { display: table-row; } .shoe-cell { display: table-cell; padding: 12rpx 20rpx; border-bottom: 1rpx solid #eee; }这样showdown.js解析| 鞋面材质 | Flyknit |时,会生成语义化的view结构,而非原生<table>,避免小程序渲染兼容性问题。
5. 真机调试与发布前必检清单:从project.config.json到微信审核红线
5.1project.config.json中影响真机体验的关键配置
project.config.json的"minPlatformVersion"字段决定最低兼容基础库版本:
"minPlatformVersion": "2.25.2"该版本支持wx.getFileSystemManager()的readdir方法,用于批量读取assets/fonts/下的球鞋字体文件。若设为2.20.0,则index.js中的字体加载会失败。
"compileType"必须为"miniprogram",若误设为"plugin",会导致app.js的onLaunch不执行。
提示:
"setting"中的"es6"应设为true,否则submitOrder.js中的箭头函数() => {}会被编译报错;"enhance"设为true启用新版setData异步机制,避免购物车数量更新延迟。
5.2 微信审核避坑指南:球鞋类目特有的敏感点
微信小程序类目审核对球鞋电商有三项硬性要求:
| 审核项 | 源码现状 | 修改建议 |
|---|---|---|
| 商品资质 | 未提供《医疗器械经营许可证》等文件 | 若销售联名款(如 Nike x Off-White),需在「小程序管理后台→资质证明」上传联名授权书扫描件 |
| 价格展示 | index.wxml中{{item.price}}未标注货币单位 | 在 WXML 中改为¥{{item.price}},且price字段必须为数字类型,禁止字符串"¥1299" |
| 客服响应 | kefu.jpg仅为静态图,无跳转逻辑 | 在bindtap="openKefu"对应方法中,必须调用wx.openCustomerServiceConversation(),且ext参数需传入用户ID |
openKefu方法必须包含:
openKefu: function() { wx.openCustomerServiceConversation({ ext: JSON.stringify({ userId: getApp().globalData.userId }), success: () => console.log('客服会话打开成功') }); }若缺少ext参数,审核时会因「客服功能不可用」被拒。
5.3 发布前性能压测:Lighthouse 分数与首屏时间达标线
使用微信开发者工具「调试器→Network」录制首页加载过程,重点关注:
- 首屏时间(FCP):应 ≤1.2s(iPhone 12 真机实测)
- JS 执行时间:
app.js+index.js总执行时长 ≤300ms - 图片请求数:首屏图片 ≤6 张(含占位图)
若 FCP 超标,按优先级检查:
app.js中onLaunch是否有阻塞操作(如同步读取大JSON);index.js的onLoad是否发起多个并发请求(应合并为单次POST /shoes/list);assets/images/下是否存在未压缩的 PNG(>200KB)。
最终验证命令:
在开发者工具控制台执行:
# 检查购物车数据一致性 console.log('购物车数量:', getApp().globalData.cartList.filter(i=>i.selected).length); # 检查客服跳转可用性 wx.canIUse('openCustomerServiceConversation') // 应返回 true确认全部通过后,即可提交审核。
本文还有配套的精品资源,点击获取