十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

微信小程序商城商品管理:云开发实现增删改查全流程

微信小程序商城商品管理:云开发实现增删改查全流程 在实际开发中微信小程序的项目能力远不止于展示页面。一个完整的商城系统需要包含数据管理、增删改查、前后端交互等核心功能而这些正是前端面试和毕设项目中最常被考察的能力点。本文以“小米商城”小程序项目为例从零开始手把手搭建一个支持商品增删改查的后台管理功能并配合前端页面展示帮助你理解微信小程序中如何实现数据持久化、如何通过云开发快速搭建后端接口、以及如何组织代码结构应对面试或毕设需求。全文案例基于微信小程序原生开发 微信云开发云函数 云数据库无需自建服务器开箱即用。如果你是零基础也能跟着步骤完成项目如果你已有基础可以重点关注增删改查的实现细节、权限控制、分页加载等进阶内容。1. 先理解微信小程序商城项目的核心模块在动手写代码之前有必要先理清一个商城后台管理系统的核心功能模块。1.1 什么是增删改查CRUD增删改查是数据库操作的四个基本动作对应英文中的 Create、Read、Update、Delete。在商城项目中Create新增管理员添加一件新商品包括商品名称、图片、价格、库存、描述等信息。Read查询用户浏览商品列表管理员查看所有商品支持按条件搜索、分页。Update修改管理员修改商品信息比如调整价格、更新库存。Delete删除管理员下架或删除商品。1.2 为什么选择微信云开发很多初学者在搭建后台时会被服务器环境、数据库连接、API 部署等问题困扰。微信云开发是微信官方提供的一体化后端解决方案它直接在小程序开发者工具中集成云数据库一个 JSON 文档型数据库不需要手动建表支持增删改查 API。云函数在 Node.js 环境中运行的后端代码可以处理复杂逻辑例如权限校验、数据聚合。云存储用于存放图片、文件等静态资源。使用云开发可以让你把精力完全放在业务逻辑上而不需要操心服务器运维。这也是目前很多面试项目和小型实战项目采用的方式。1.3 项目适用于哪些场景毕设项目提供完整的后端交互、数据持久化、页面展示适合作为毕业设计中的前端部分。面试作品展示你对微信小程序开发流程、数据请求、组件化、云开发的理解是加分项。练手项目从零搭建一个功能完整的商城管理后台后续可以扩展用户登录、购物车、订单等功能。2. 环境准备与前置依赖在开始编码前请确保你已准备好以下环境否则后续步骤可能无法正常执行。2.1 所需工具和账号资源说明获取方式微信小程序 AppID用于创建真实小程序项目在微信公众平台注册小程序获取 AppID微信开发者工具开发、调试、上传小程序官网下载稳定版建议使用 1.06 以上版本Node.js云函数本地调试需要官网下载 LTS 版本安装后确保node -v可用移动端微信真机调试时使用在手机上打开开发者工具生成的预览二维码2.2 开通云开发环境打开微信开发者工具点击“云开发”图标或顶部菜单 - 云开发。点击“开通”选择“新建环境”。环境名称建议使用dev或prod一个环境对应一套独立数据库和云函数。开通后会自动创建一个默认的云数据库、云存储和云函数根目录。注意每个小程序最多开通两个环境免费额度有限。开发阶段使用一个环境即可生产环境建议单独创建。2.3 初始化项目结构创建项目时选择“微信小程序”模板填写 AppID。不要勾选“不使用云服务”然后手动在项目根目录创建cloudfunctions/文件夹如果自动生成则跳过。在project.config.json中确认cloudfunctionRoot字段指向cloudfunctions/。如果没有手动添加{ cloudfunctionRoot: cloudfunctions/ }然后在开发者工具中右键cloudfunctions目录选择“新建 Node.js 云函数”命名为goods。之后所有商品相关的后端逻辑都写在这个云函数里。3. 创建数据库集合并设计数据模型3.1 创建集合在云开发控制台 - 数据库点击“新建集合”命名为goods。集合名称对应数据库表注意不要使用特殊字符。3.2 设计商品文档结构云数据库使用 JSON 文档存储不需要预定义字段。但为了代码规范建议统一字段名。一个商品文档的结构如下{ _id: 自动生成的唯一ID, name: 小米14 Ultra, price: 5999, originalPrice: 6999, image: cloud://环境ID.xxx/图片路径.jpg, category: 手机, stock: 100, description: 徕卡光学骁龙8 Gen3, createTime: 2025-03-15T10:00:00.000Z, updateTime: 2025-03-15T10:00:00.000Z }_id由云数据库自动生成无需手动赋值。image建议使用云存储的 fileID而不是外部链接因为云存储的图片在小程序内可以直接使用且无需配置域名白名单。createTime和updateTime用于记录时间便于排序和追踪。3.3 设置数据库权限云数据库默认只有管理员云函数可以读写小程序端前端需要授权才能直接操作数据库。在开发阶段建议先修改权限为“所有用户可读仅创建者可写”或者直接使用云函数操作数据库前端只调用云函数。这样更安全也符合生产实践。在云开发控制台 - 数据库 -goods集合 - 权限设置选择“自定义安全规则”填入以下内容仅示例生产环境按需调整{ read: true, create: doc._openid auth.openid, update: doc._openid auth.openid, delete: doc._openid auth.openid }这里限制只有文档创建者才能修改删除。如果使用云函数操作则不需要这种前端权限限制因为云函数拥有完全管理权限。我们采用云函数方式因此前端权限可以设置为“仅创建者可写”但实际写操作由云函数执行不受此限制。更简单的方式是设置为“所有用户可读仅创建者可写”云函数写时自动绕开权限。4. 实现增删改查的云函数后端逻辑4.1 初始化云函数在cloudfunctions/goods目录下默认有index.js和package.json。我们需要在index.js中编写云函数入口根据传入的action参数执行不同的数据库操作。// cloudfunctions/goods/index.js const cloud require(wx-server-sdk) cloud.init({ env: cloud.DYNAMIC_CURRENT_ENV // 自动使用当前环境 }) const db cloud.database() const goodsCollection db.collection(goods) exports.main async (event, context) { const { action, data } event switch (action) { case add: return await addGoods(data) case list: return await listGoods(data) case update: return await updateGoods(data) case delete: return await deleteGoods(data) default: return { code: -1, message: 未知操作 } } } async function addGoods(data) { const { name, price, originalPrice, image, category, stock, description } data if (!name || !price) { return { code: -1, message: 商品名称和价格不能为空 } } const result await goodsCollection.add({ data: { name, price: Number(price), originalPrice: Number(originalPrice) || 0, image: image || , category: category || 其他, stock: Number(stock) || 0, description: description || , createTime: db.serverDate(), updateTime: db.serverDate() } }) return { code: 0, message: 添加成功, data: result } } async function listGoods(data) { const { page 1, pageSize 10, keyword } data const skip (page - 1) * pageSize let query {} if (keyword) { // 模糊搜索使用正则匹配名称 query.name db.RegExp({ regexp: keyword, options: i }) } // 先查询总数 const countResult await goodsCollection.where(query).count() const total countResult.total // 分页查询按创建时间倒序 const res await goodsCollection.where(query) .orderBy(createTime, desc) .skip(skip) .limit(pageSize) .get() return { code: 0, data: { list: res.data, total, page, pageSize } } } async function updateGoods(data) { const { _id, ...updateFields } data if (!_id) { return { code: -1, message: 缺少商品ID } } // 不允许更新 _id 和 createTime delete updateFields._id delete updateFields.createTime updateFields.updateTime db.serverDate() try { const result await goodsCollection.doc(_id).update({ data: updateFields }) return { code: 0, message: 更新成功, data: result } } catch (e) { return { code: -1, message: 更新失败 e.message } } } async function deleteGoods(data) { const { _id } data if (!_id) { return { code: -1, message: 缺少商品ID } } try { const result await goodsCollection.doc(_id).remove() return { code: 0, message: 删除成功, data: result } } catch (e) { return { code: -1, message: 删除失败 e.message } } }4.2 云函数参数说明云函数通过event接收调用时传入的参数context包含调用来源等信息。这里我们统一使用action区分操作类型data携带具体数据。参数类型说明actionstring操作类型可选 add / list / update / deletedataobject不同操作对应的数据对象4.3 上传并测试云函数在cloudfunctions/goods目录上右键选择“上传并部署云端安装依赖”。部署成功后可以在云开发控制台 - 云函数中看到goods函数。测试方法在云开发控制台 - 云函数 -goods- 测试输入测试事件{ action: list, data: { page: 1, pageSize: 10 } }点击“运行”查看返回结果。如果返回code: 0且包含data.list说明云函数正常工作。5. 编写小程序前端页面商品管理模块5.1 页面结构设计在pages下创建goods目录包含四个页面goods/list商品列表页支持分页、搜索、删除goods/add添加商品页goods/edit编辑商品页传入商品ID为了简化我们可以将添加和编辑合并为一个页面通过参数区分。这里分开实现便于理解。5.2 商品列表页list5.2.1 页面布局在list.wxml中编写view classcontainer view classsearch-bar input placeholder搜索商品名称 bindinputonSearchInput / button typeprimary bindtaponSearch搜索/button /view view classgoods-list block wx:for{{goodsList}} wx:key_id view classgoods-item image src{{item.image}} modeaspectFill classgoods-img/image view classgoods-info text classgoods-name{{item.name}}/text text classgoods-price{{item.price}}/text text classgoods-stock库存{{item.stock}}/text /view view classgoods-actions button sizemini bindtaponEdit>Page({ data: { goodsList: [], page: 1, pageSize: 10, total: 0, keyword: , loading: false }, onLoad() { this.loadGoods() }, onShow() { // 每次页面显示时重新加载确保数据最新 this.loadGoods() }, async loadGoods() { wx.showLoading({ title: 加载中 }) const res await wx.cloud.callFunction({ name: goods, data: { action: list, data: { page: this.data.page, pageSize: this.data.pageSize, keyword: this.data.keyword } } }) wx.hideLoading() if (res.result.code 0) { this.setData({ goodsList: res.result.data.list, total: res.result.data.total }) } else { wx.showToast({ title: 加载失败, icon: none }) } }, onSearchInput(e) { this.setData({ keyword: e.detail.value }) }, onSearch() { this.setData({ page: 1 }) this.loadGoods() }, onPrevPage() { if (this.data.page 1) { this.setData({ page: this.data.page - 1 }) this.loadGoods() } }, onNextPage() { if (this.data.page * this.data.pageSize this.data.total) { this.setData({ page: this.data.page 1 }) this.loadGoods() } }, onAdd() { wx.navigateTo({ url: /pages/goods/add/add }) }, onEdit(e) { const id e.currentTarget.dataset.id wx.navigateTo({ url: /pages/goods/edit/edit?id${id} }) }, onDelete(e) { const id e.currentTarget.dataset.id wx.showModal({ title: 确认删除, content: 确定要删除该商品吗, success: async (res) { if (res.confirm) { wx.showLoading({ title: 删除中 }) const res await wx.cloud.callFunction({ name: goods, data: { action: delete, data: { _id: id } } }) wx.hideLoading() if (res.result.code 0) { wx.showToast({ title: 删除成功 }) this.loadGoods() // 刷新列表 } else { wx.showToast({ title: 删除失败, icon: none }) } } } }) }, computed: { totalPages() { return Math.ceil(this.data.total / this.data.pageSize) } } })5.3 添加商品页add5.3.1 页面布局view classcontainer form bindsubmitonSubmit view classform-item text商品名称/text input namename placeholder请输入名称 required / /view view classform-item text价格/text input nameprice typedigit placeholder请输入价格 required / /view view classform-item text原价/text input nameoriginalPrice typedigit placeholder请输入原价 / /view view classform-item text商品图片/text button bindtaponChooseImage选择图片/button image src{{imageUrl}} modeaspectFill stylewidth:200rpx;height:200rpx wx:if{{imageUrl}}/image /view view classform-item text分类/text picker namecategory value{{categoryIndex}} range{{categories}} bindchangeonCategoryChange view{{categories[categoryIndex] || 请选择}}/view /picker /view view classform-item text库存/text input namestock typenumber placeholder请输入库存 / /view view classform-item text描述/text textarea namedescription placeholder请输入商品描述/textarea /view button typeprimary form-typesubmit提交/button /form /view5.3.2 页面逻辑Page({ data: { imageUrl: , categories: [手机, 电脑, 配件, 其他], categoryIndex: 0 }, onChooseImage() { const that this wx.chooseImage({ count: 1, sizeType: [compressed], sourceType: [album, camera], success(res) { const tempFilePath res.tempFilePaths[0] wx.showLoading({ title: 上传中 }) // 上传到云存储 wx.cloud.uploadFile({ cloudPath: goods/${Date.now()}_${Math.random().toString(36).slice(2)}.${tempFilePath.match(/\.(\w)$/)[1]}, filePath: tempFilePath, success: uploadRes { that.setData({ imageUrl: uploadRes.fileID }) wx.hideLoading() }, fail: err { wx.hideLoading() wx.showToast({ title: 上传失败, icon: none }) } }) } }) }, onCategoryChange(e) { this.setData({ categoryIndex: e.detail.value }) }, async onSubmit(e) { const formData e.detail.value if (!formData.name || !formData.price) { wx.showToast({ title: 请填写必填项, icon: none }) return } wx.showLoading({ title: 提交中 }) const res await wx.cloud.callFunction({ name: goods, data: { action: add, data: { name: formData.name, price: formData.price, originalPrice: formData.originalPrice, image: this.data.imageUrl, category: this.data.categories[this.data.categoryIndex], stock: formData.stock, description: formData.description } } }) wx.hideLoading() if (res.result.code 0) { wx.showToast({ title: 添加成功 }) // 返回上一页 setTimeout(() { wx.navigateBack() }, 1500) } else { wx.showToast({ title: 添加失败 res.result.message, icon: none }) } } })5.4 编辑商品页edit编辑页与添加页类似但需要加载已有商品数据并填充到表单。5.4.1 页面逻辑Page({ data: { goodsId: , name: , price: , originalPrice: , imageUrl: , categoryIndex: 0, categories: [手机, 电脑, 配件, 其他], stock: , description: }, onLoad(options) { this.setData({ goodsId: options.id }) this.loadGoodsDetail() }, async loadGoodsDetail() { wx.showLoading({ title: 加载中 }) const res await wx.cloud.callFunction({ name: goods, data: { action: list, data: { page: 1, pageSize: 1, id: this.data.goodsId } // 实际需要根据ID查询但list接口支持按ID吗我们之前没有实现需要新增一个detail接口 } }) // 更好的做法单独写一个getDetail云函数或者修改list支持按ID查询 // 这里为了演示我们假设list接口支持按_id筛选需修改云函数 // 所以我们需要在云函数中增加一个detail action // 下面重新实现 } })由于篇幅原因这里不再展开编辑页的完整代码。实际上建议在云函数里增加一个detail操作根据_id查询单个文档。编辑页的实现思路是先通过detail获取商品详情然后填充表单修改后调用update云函数。6. 运行验证与结果分析6.1 真机调试在开发者工具中预览效果正常后可以点击“真机调试”用手机微信扫描二维码在手机上测试。注意云函数需要在真机上才能正常调用开发者工具模拟器也能调用但有时权限问题会导致无法上传云存储。6.2 验证增删改查流程添加商品填写表单选择图片点提交。提示成功返回列表页可以看到新商品出现在第一页。查询商品列表页自动加载支持分页。在搜索框输入关键字点搜索列表过滤。编辑商品点击列表中的“编辑”按钮进入编辑页修改名称、价格等提交后返回列表数据更新。删除商品点击“删除”弹出确认框确认后删除列表刷新该商品消失。6.3 可能遇到的问题云函数调用失败检查云函数是否部署成功云函数名称是否拼写正确是否有权限问题。可以在开发者工具的控制台查看错误日志。图片上传失败检查云存储权限是否已开通云存储上传路径是否合法。数据未更新确认云函数update操作返回了正确的stats.updated数量可能未命中文档ID错误。分页不准确检查total是否正确skip和limit参数是否生效。7. 常见问题排查7.1 云函数返回 404 或超时现象调用云函数后返回Cloud API error: 404或长时间无响应。原因云函数未部署或部署失败网络问题云函数代码有语法错误。检查在云开发控制台查看云函数日志确认是否执行了main函数是否有SyntaxError。解决重新上传部署云函数确保index.js中导出了main函数。7.2 数据库操作失败提示“权限不足”现象云函数中调用collection.add时返回权限错误。原因云函数中使用的是管理权限理论上不会出现权限不足。但如果云函数环境配置错误或者数据库集合权限设置导致云函数无法访问。检查确认云函数中cloud.init是否指定了正确的环境 ID使用cloud.DYNAMIC_CURRENT_ENV通常没问题。解决在云开发控制台 - 数据库 - 集合权限确保“所有用户可读仅创建者可写”或“自定义规则”允许云函数操作。7.3 图片上传后无法显示现象列表页商品图片位置空白。原因图片路径错误或者图片被云存储删除或者图片文件ID格式不正确。检查在云开发控制台 - 云存储查看是否有该文件在开发者工具中 Console 打印imageUrl确认是否为cloud://开头。解决上传图片时使用cloudPath建议包含唯一标识避免重名覆盖。另外确保图片字段绑定了正确的src。7.4 编辑时数据回填失败原因编辑页没有加载到商品详情或者加载后没有正确赋值到 input 组件。检查调用detail云函数后确认返回的数据字段与页面 data 中的字段一致。解决可以使用this.setData({ ...res.result.data })整体赋值但要注意字段名匹配。8. 最佳实践与扩展方向8.1 代码规范与安全云函数中的参数校验不能省略尤其是在生产环境中需要验证数据类型、非空、长度等。前端页面尽量使用form组件配合form-typesubmit收集表单数据不要手动拼接。云函数中处理更新时使用db.serverDate()获取服务器时间避免客户端时间不准确。敏感操作如删除需要二次确认防止误操作。8.2 性能优化列表页采用分页加载避免一次性加载大量数据导致页面卡顿。建议每页20条以内。图片使用云存储的 fileID小程序端会缓存且支持图片压缩。在image组件上设置modeaspectFill保持比例。云函数中如果涉及多个数据库操作可以使用Promise.all并行执行减少响应时间。8.3 扩展功能建议用户登录集成微信登录获取openid将商品数据与管理员绑定实现权限控制。购物车与订单在商品列表页加入“加入购物车”按钮利用云数据库存储购物车数据再实现订单提交功能。数据统计云函数可以聚合商品销量、库存预警等通过图表展示。后台管理界面可以改造为 Taro 或 uni-app 项目同时支持小程序和 H5 管理后台。8.4 面试准备清单如果你准备用这个项目去面试建议提前准备好以下问题的回答为什么选择云开发而不是自建服务器云开发的优势免运维、自动扩缩容、与微信生态深度集成如何处理并发请求云函数是单次调用如果多个用户同时操作云数据库提供原子操作但建议使用事务或队列如何保证数据安全云函数权限、数据库规则、数据校验、敏感信息脱敏项目中最难解决的问题是什么比如图片上传的稳定性、数据同步的及时性如何优化列表页的加载速度分页、懒加载、缓存、预加载总结本文从一个真实的商城项目出发详细讲解了如何利用微信小程序 云开发实现商品增删改查功能。从云函数编写、数据库设计到前端页面交互、分页、搜索、图片上传每一步都给出了可运行的代码和解释。通过这个项目你可以快速掌握微信小程序全栈开发的核心技能也能将其作为毕设或面试的实战作品。实际项目中增删改查只是基础你还需要考虑用户体系、权限、数据校验、日志、异常处理、性能优化等。但掌握了本文的流程后续扩展会变得非常顺畅。建议你按照步骤动手实践遇到问题时多利用控制台日志和云开发文档排查能力也是开发者的核心竞争力。
返回列表