ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

微信小程序商城源码解析:从app.json到模板复用的实战指南

微信小程序商城源码解析:从app.json到模板复用的实战指南 简介压缩包提供了一套生鲜商城小程序的前端工程源码主要面向小程序开发初学者、电商项目实训者以及相关毕业设计学生。资源体积仅为54KB却包含了44个文件其中代码文件以wxml、wxss、js、json四类为主并配有png图标素材、使用说明txt、启动更新bat及更多资料链接等辅助内容。通过研读源码可以系统学习生鲜电商六大核心功能模块——商品分类展示、关键词搜索、购物车管理、在线支付、订单物流跟踪以及用户评价——的具体编码方式同时掌握页面生命周期、数据缓存和组件化封装等微信小程序高阶开发技巧。项目界面清爽基于原生组件构建适配不同移动屏幕后端接口预留清晰便于本地联调或替换为云服务。目前已有195人学习下载项目注释规范、模块划分合理既适合逐行精读也适合在此基础上快速扩展个性化功能是电商类小程序开发中一份高性价比的参考资源。1. 生鲜商城小程序源码包pages 目录与模板文件的工程定位如果你正打算找一份微信小程序项目实例来改造或者课程设计需要一个能跑起来的商城底座这个压缩包值得先花十分钟拆开看结构而不是直接导入开发者工具。它不是一个几十个页面的完整电商系统而是“商城骨架 教学演示”的混合工程pages 下只有 index、list、component、logs 四个页面index 负责商品流list 是分类列表component 演示微信 API 与组件用法logs 是模板自带的启动日志页。最值钱的东西在 template/item-template.wxml 这个商品卡片模板以及 app.json 里成对出现的 tabBar 图标命名。小程序商城这类项目真正决定后期改造成本的往往不是页面数量而是模板、配置、工具函数的分层是否清晰。先别急着改代码把全局配置和页面路由读明白后面接真实接口时才不会到处返工。2. app.json 全局配置与页面路由先把商城骨架搭对微信小程序项目实例里app.json 是第一个被执行的配置文件比 app.js 更早决定入口和导航形态。解压这个 zip 后在根目录打开 app.json结构大致如下{ pages: [ pages/index/index, pages/list/list, pages/component/component, pages/logs/logs ], window: { navigationBarBackgroundColor: #1FA45B, navigationBarTitleText: 生鲜商城, navigationBarTextStyle: white, backgroundColor: #F6F6F6 }, tabBar: { color: #999999, selectedColor: #1FA45B, list: [ { pagePath: pages/index/index, text: 购买, iconPath: icon_API.png, selectedIconPath: icon_API_HL.png }, { pagePath: pages/component/component, text: 组件, iconPath: icon_component.png, selectedIconPath: icon_component_HL.png }, { pagePath: pages/logs/logs, text: 我的, iconPath: wechat.png, selectedIconPath: wechatHL.png } ] }, networkTimeout: { request: 10000 } }pages 数组的第一项是启动页整个底部导航的图标路径正好对应压缩包里那几张 PNG 图片。这说明这些图片不是装饰文件而是给 tabBar 用的资源。这里有一个非常容易踩的坑tabBar 的 list 至少 2 项、至多 5 项每一项必须同时具备 iconPath 和 selectedIconPath只放一张图会直接编译报错。后续要换图标记得准备普通态和选中态两套图。2.1 pages 注册顺序决定入口component 与 logs 是功能性页面四个页面的分工可以用一张表说清楚页面路径角色职责pages/index/index商品首页商品流入口承载模板渲染的商品列表pages/list/list商品列表页分类筛选、搜索结果展示pages/component/component组件与 API 演示演示 icon_API、icon_component 相关能力pages/logs/logs日志页微信模板自带配合 util.js 看启动记录index 和 list 拆开是为了承担两种导航方式tabBar 直达首页wx.navigateTo 带参进入列表页。实际改造时新建商品详情页必须同步加进 pages 数组否则运行到wx.navigateTo({ url: /pages/goods-detail/goods-detail })会直接报错页面不存在。logs 页的存在说明作者保留了新手工程的自带页面component 页则承担了展示微信 API 调用的教学功能这也是这个包被不少课程设计选中的原因。2.2 window 与 tabBar 的参数边界window 配置里值得注意两个细节。第一navigationBarBackgroundColor 用深绿 #1FA45B 是生鲜主题里很常见的做法navigationBarTextStyle 只有 black 和 white 可选白色字必须配深色背景否则视觉上看不清。第二backgroundColor 是下拉露出的背景色不是页面主体背景页面背景要在 app.wxss 里通过 page 选择器设置这两个概念经常被混在一起。networkTimeout 只对 wx.request、wx.uploadFile 这类网络 API 生效超时后走 fail 回调而不是直接抛异常所以接口层要自己封装超时提示不能依赖框架弹错。2.3 公共样式与工具函数的分层策略这个包在样式和工具函数上的分法是值得沿用的。app.wxss 放全局公共类比如 button 默认样式重置、边框清除style/layout.wxss 放布局类flex 主轴方向、商品卡片阴影、栅格间距页面自己的 wxss 只写页面私有样式。utils/util.js 里通常是 formatTime、request 封装、防抖节流这类纯函数。这种分层的好处在于后面接真实接口时只需要改 util.js 的请求方法和 baseURL页面逻辑不用动。很多新手做小程序商城时把所有样式堆在一个 wxss 里等到页面超过五个改一个间距就要全局搜索成本完全不一样。3. item-template 商品模板复用列表渲染与购物车交互商品卡片是这个项目复用性最强的一块。template/item-template.wxml 放在根目录 template 下而没有塞进 pages说明它要被 index 和 list 两个页面共用。微信小程序的 template 复用机制靠 import 引入模板里可以写事件绑定但对应函数必须定义在使用模板的页面里这是它和 Vue 组件最大的区别。模板只解决视图复用不解决逻辑复用逻辑仍然在页面 js 中。3.1 import 引入模板的两种数据传递写法在 index 页面引入模板的典型写法是!-- pages/index/index.wxml -- import src../../template/item-template.wxml / view classgoods-list block wx:for{{goodsList}} wx:keyid template isitem-template data{{item}} / /block /viewis 的值必须和模板内定义的 name 完全一致wx:key直接写id字符串不要写成wx:key{{id}}后者拿不到字段名。data 不传的话模板里拿到的都是 undefined。模板文件内部的结构大致是template nameitem-template view classcard bindtapgoDetail>// pages/index/index.js Page({ data: { goodsList: [], cartCount: 0 }, addCart(e) { const id Number(e.currentTarget.dataset.id); const product this.data.goodsList.find(v v.id id); if (!product) return; const cart wx.getStorageSync(cart) || []; const exist cart.find(v v.id id); if (exist) { exist.count 1; } else { cart.push(Object.assign({}, product, { count: 1 })); } wx.setStorageSync(cart, cart); const total cart.reduce((sum, v) sum v.count, 0); this.setData({ cartCount: total }); wx.showToast({ title: 已加入购物车, icon: success }); } });用 e.currentTarget.dataset.id 而不是 e.targetcurrentTarget 是绑定事件的元素target 可能是点击到的子元素两者在图片上点击时结果会不一样。dataset 读出来的值默认是字符串商品 id 是数字时要做 Number 转换否则 find 的严格相等比较会失配。购物车数据写进本地缓存后页面刷新加购记录还在这是小程序商城在没有登录体系时最轻量的持久化方案。库存字段可以在商品对象里加 stock在下单前校验。4. 页面生命周期与数据流从本地模拟数据到 wx.request模板只解决视图复用数据流靠 Page 生命周期和 app.js 的全局对象协作。这个工程里 index 和 list 都有商品列表需求如果各自请求一遍接口切换 tab 会重复拉数据。常见的做法是购物车放 globalData商品列表留在页面自己的 data 中因为列表数据每个页面展示维度不同强行走全局会引入不必要的耦合。4.1 生命周期选择onLoad 拉数据onShow 刷新角标app.js 里初始化购物车让全局数据和本地缓存保持一致// app.js App({ globalData: { cart: [] }, onLaunch() { const cart wx.getStorageSync(cart); if (cart) this.globalData.cart cart; } });页面在 onLoad 中读取商品列表在 onShow 中刷新购物车角标这是小程序商城里很典型的生命周期分配// pages/list/list.js const app getApp(); const goods require(../../data/goods.js); // 本地模拟数据接口就绪后替换为 wx.request Page({ data: { goodsList: [], cartCount: 0 }, onLoad() { this.setData({ goodsList: goods.list }); }, onShow() { const cart (app.globalData.cart app.globalData.cart.length) ? app.globalData.cart : wx.getStorageSync(cart) || []; const count cart.reduce((sum, v) sum v.count, 0); this.setData({ cartCount: count }); } });globalData 在冷启动后才被 onLaunch 填充如果页面生命周期先于 onLaunch 完成直接读 globalData.cart 可能拿到空数组所以 onShow 里做一次 storage 兜底读取。这里的 reduce 累加的是 count 字段而不是数组长度因为同一个商品可能加购多次。生命周期各阶段的适用场景可以对照来看生命周期触发时机典型用途onLoad页面创建时一次拉取商品列表、读取导航参数onShow每次显示刷新购物车角标onReady首次渲染完成wx.createSelectorQuery 查节点onHide页面隐藏自动保存草稿onUnload页面销毁清理定时器4.2 util.js 请求封装与真实接口切换商城接后端时直接在页面里写 wx.request 会让十几个页面各自维护一套 header 和错误处理。可以收敛到 utils/util.js 里做一个 Promise 封装const BASE_URL https://api.example.com; function request(path, method GET, data {}) { const token wx.getStorageSync(token); return new Promise((resolve, reject) { wx.request({ url: BASE_URL path, method, data, header: Object.assign( { Content-Type: application/json }, token ? { Authorization: Bearer token } : {} ), success(res) { if (res.statusCode 200 res.statusCode 300) resolve(res.data); else if (res.statusCode 401) { wx.removeStorageSync(token); wx.navigateTo({ url: /pages/login/login }); reject(res); } else reject(res); }, fail: reject }); }); } module.exports { request };BASE_URL 上线后必须是 https 并且在小程序后台配置合法域名开发阶段可以在开发者工具里勾选“不校验合法域名”。401 统一清 token 并跳登录页比每个页面重复判断业务状态码干净得多。需要并发请求时用 Promise.all 同时拉轮播图和商品列表两个接口互不阻塞。提示开发者工具里“不校验合法域名”只用于开发阶段上线前必须在公众平台配置 request 合法域名否则 Android 真机直接拒绝请求。4.3 原生小程序与 uniapp 的工程差异这个 zip 是原生微信小程序构建方式是通过微信开发者工具直接打开目录。如果你习惯 uniapp 的工作流两者的差异要清楚原生小程序的 app.json 对应 uniapp 的 pages.jsontabBar 的写法几乎一致但 uniapp 的 pages.json 是类 JSON 格式部分导航参数要在 manifest.json 里声明。原生项目的 WXML 模板在 uniapp 里对应的是 vue 单文件组件template 标签的 import 机制不再适用而是组件化引入。团队项目如果只有微信一个端原生方案足够模板复用反而更轻。如果要同时发支付宝、抖音小程序迁移到 uniapp 等于重写页面层业务逻辑可以保留成本主要花在模板语法转换上。个人项目或毕设场景原生项目上手最快调样式和看报错都比跨端框架直观。5. 上架前的配置收尾备案、动态标题与真机排错从 demo 到能发体验版中间隔着几个容易忽略的配置项备案、支付资质、页面标题和导航栏适配。这些不处理好代码写完了也上不了线。5.1 备案、支付资质与备注信息填写微信公众平台注册后先在“设置-基本设置”拿到 AppID填入项目根目录 project.config.json。小程序备案在公众平台后台提交主体信息要和营业执照一致。服务内容类目选“食品-生鲜/农副产品”备注一栏不要只写“生鲜电商”建议写清楚商品来源、配送方式和售后渠道例如“销售本地农场直供果蔬自建冷链配送48小时内售后响应”。如果你的主体是个人微信支付无法开通小程序内会出现“支付能力已被限制”这是资质问题而不是代码问题换企业主体重新提交审核即可。5.2 动态标题与导航栏适配分类列表页需要跟随点击改变标题用 wx.setNavigationBarTitle 在 onLoad 或 onShow 里调用。注意这个 API 只能在 Page 实例中调用不能在 App 的 onLaunch 里执行。自绘导航栏时用 getMenuButtonBoundingClientRect 拿到胶囊按钮位置再计算导航栏高度const menu wx.getMenuButtonBoundingClientRect(); const statusBarHeight wx.getSystemInfoSync().statusBarHeight; const navHeight (menu.top - statusBarHeight) * 2 menu.height;这段代码计算出的 navHeight 用于自定义顶部栏时保持一致的高度避免在 iPhone 刘海屏和普通屏之间来回跳动。开发工具模拟器和真机返回值不同以真机为准。上传代码到公众平台后体验版如果白屏先看 Console 报错是不是 app.json 里 tabBar 图标路径不对。图标缺失比业务逻辑报错出现得更早检查顺序应该是app.json 语法、pages 数组路径、tabBar 图标是否存在、页面 json 的 usingComponents 是否写错。出现Unable to resolve module ./item-template这类报错先数 import 路径的回退层级pages/index/index 访问根目录 template 要回退两级写成 ../../template/item-template少一个点都找不到模块。本文还有配套的精品资源点击获取
返回列表