
摘要后端 API 全部就绪了Day01-16但用户总不能抱着 Postman 购物吧今天把前端搞起来——用 uni-app Vue3 从零搭建商城小程序。涵盖项目初始化、五大核心页面首页/商品详情/购物车/订单/个人中心、组件化开发、Pinia 全局状态管理。成本依然是零。后端 API 写好了然后呢过去 16 天我们把商城的后端搭得明明白白Django DRF 框架稳稳当当商品、订单、用户、支付、客服……接口全齐了统一的响应格式{code: 0, message: success, data: ...}但问题来了——用户怎么用你不会真的让用户打开 Postman填个 POST 请求来买东西吧那大概是客户流失最快的电商了。我们需要一个前端。一个能在手机上跑的、界面好看的、交互流畅的前端。为什么选 uni-app一套代码多端运行微信小程序、支付宝小程序、H5、App……写一次到处跑Vue3 生态Composition API、Pinia 状态管理国内生态好插件市场丰富踩坑有人帮今天就从零开始把商城的小程序前端搭起来。uni-app 和 Vue3 的组合拳uni-app 是什么一句话用 Vue 的语法写跨平台应用。你的 Vue3 代码 │ ├── 编译 → 微信小程序WXML WXSS JS ├── 编译 → 支付宝小程序 ├── 编译 → H5网页版 └── 编译 → AppiOS / Android底层是编译器 运行时。你写的是标准 Vue3 代码uni-app 帮你翻译成各平台的原生代码。Vue3 Composition APIVue3 最核心的变化是 Composition API。相比 Options API 那种 data/methods/computed 分家的写法Composition API 让你按功能组织代码// Options API按类型分家exportdefault{data(){return{count:0}},methods:{increment(){this.count}},computed:{double(){returnthis.count*2}}}// Composition API按逻辑聚合import{ref,computed}fromvueconstcountref(0)constincrement()count.valueconstdoublecomputed(()count.value*2)PiniaVue3 的官方状态管理Vuex 已经是过去式了。Pinia 的优势很明显API 更简洁没有 mutations直接改 stateTypeScript 友好类型推导完美体积更小核心代码不到 1KB支持 Composition APIsetup语法无缝集成购物车数据、用户登录状态……这些跨页面共享的数据用 Pinia 管理再合适不过。动手实战项目初始化# 拉取 uni-app Vue3 模板vite-ts 自带 TypeScriptnpx degit dcloudio/uni-preset-vue#vite-ts mei-ya-da-appcdmei-ya-da-appnpminstall# 安装 Pinia 持久化插件刷新/杀掉小程序不丢数据npminstallpinianpminstallpinia-plugin-persisted-uniapp初始化完成后目录按功能分层mei-ya-da-app/src/ ├── api/ # 接口请求封装request.ts 基础封装 按模块分的接口文件 ├── components/ # 通用组件ProductCard、NavBar、CartModal、EmptyState ├── composables/ # 组合式函数useAuth、useCart ├── pages/ # 页面index 首页 / product 详情 / cart 购物车 / order 订单 / mine 我的 ├── stores/ # Pinia 状态cart 购物车 / user 用户 ├── static/ # 静态资源 └── styles/ # 全局样式这个结构看着复杂其实就是按功能分层。api 管网络、components 放组件、pages 放页面、stores 放状态。找代码一目了然。请求封装api/request.ts所有接口请求的底层封装统一处理 Base URL、Token 注入、错误拦截。核心逻辑三段exportfunctionrequestT(options):PromiseT{returnnewPromise((resolve,reject){// ① 从本地存储取 Token注入请求头 Authorizationconsttokenuni.getStorageSync(token)||uni.request({url:BASE_URLoptions.url,method:options.method||GET,header:{Content-Type:application/json,Authorization:token?Bearer${token}:},success:(res){constdatares.data// ② 统一响应格式 {code:0, message, data} —— code 0 成功取 data.data// ③ code 401 说明 Token 过期 → 清 Token、提示登录、跳转// 其他 code → 弹出后端返回的错误信息},})})}这段代码做了三件事① 自动在请求头加 Token② 自动解析后端统一响应格式③ 401 自动跳登录。前端所有接口调用都走这个封装。页面路由配置pages.json底部导航栏四个 Tab首页、购物车、订单、我的。商品详情页不在 TabBar 里通过跳转进入。{pages:[{path:pages/index/index,style:{navigationBarTitleText:商城,enablePullDownRefresh:true}},{path:pages/product/detail,style:{navigationBarTitleText:商品详情}},{path:pages/cart/cart,style:{navigationBarTitleText:购物车}},{path:pages/order/order,style:{navigationBarTitleText:我的订单}},{path:pages/mine/mine,style:{navigationBarTitleText:个人中心,navigationStyle:custom}}],tabBar:{color:#999999,selectedColor:#FF6034,list:[{pagePath:pages/index/index,text:首页},{pagePath:pages/cart/cart,text:购物车},{pagePath:pages/order/order,text:订单},{pagePath:pages/mine/mine,text:我的}]}}五个核心页面首页pages/index/index.vue页面布局顶部搜索栏灰色圆角输入框→轮播 Banner约 180rpx 高自动播放→分类导航一行四个图标→商品瀑布流两列卡片图/名称/价格/销量。关键逻辑template !-- 搜索栏 / 轮播 Banner / 分类导航 / 两列商品网格 -- view classproduct-grid ProductCard v-forp in productList :keyp.id :productp clickgoDetail(p.id) / /view /template script setup langts // ① onMounted 并行加载轮播 分类 商品列表Promise.all // ② loadMore 分页page1 追加到列表尾部hasMore 控制是否还能加载 // ③ 下拉刷新 onMounted 重新拉取首页数据 /script商品详情页pages/product/detail.vue页面布局商品大图轮播→价格区红色大字 原价删除线 自营/包邮标签→商品标题描述→规格选择入口点开 SKU 弹窗→图文详情rich-text→底部固定操作栏收藏/客服/加入购物车/立即购买。关键逻辑script setup langts // ① loadProduct从路由参数拿 id → getProductDetail(id) 加载详情 // ② addToCart没选规格先弹 SKU 窗选了规格调 cartStore.addItem 加购 // ③ buyNow跳过购物车带 product_id sku 参数直接跳确认订单页 // ④ 图片预览 uni.previewImage / 收藏 toggleFavorite / 客服占位 /script购物车页pages/cart/cart.vue页面布局商品行勾选框 缩略图 名称规格 价格 数量步进器→底部结算栏全选 合计金额 结算按钮带件数。空车显示空状态插画 “去逛逛”。关键逻辑script setup langts // ① toggleCheck / toggleSelectAll改 checked 后调 store.updateChecked() // ② changeQty数量减到 0 时弹窗确认删除 // ③ goCheckout只取勾选商品编码后跳确认订单页 /script订单页pages/order/order.vue页面布局顶部 Tab 栏全部/待付款/待发货/待收货/已完成→订单卡片订单号状态标签 / 商品缩略图名称规格价格×数量 / 底部合计操作按钮。关键逻辑script setup langts // ① switchTab切换状态 → 重置 page1 → 重新拉取订单列表 // ② 操作按钮按 status 条件渲染待付款显示去支付/取消订单待收货显示确认收货 // ③ cancelOrder / confirmReceive先弹确认框确认后调对应 API 并刷新列表 /script个人中心pages/mine/mine.vue页面布局渐变头部圆形头像 昵称 会员标签→订单快捷入口四宫格图标→功能列表地址/优惠券/客服/关于/设置→退出登录按钮。关键逻辑script setup langts // ① 未登录时显示点击登录跳登录页 // ② 各菜单项目前是占位 toast后续接真实功能 // ③ logout弹确认框 → userStore.logout() 清 Token /script五个页面的样式SCSS篇幅长但全是通用布局代码这里不逐行贴——照着页面由哪几块组成的描述写就行布局思路比样式代码更重要。组件化开发商品卡片组件ProductCard.vue被首页、分类页、搜索结果页复用——defineProps接收商品数据defineEmits抛出点击事件父组件决定跳哪script setup langts const props defineProps{ product: { id: number; name: string; image: string; price: number } }() const emit defineEmits{ (e: click): void }() /script空状态组件EmptyState.vue——购物车空了、订单空了、搜索没结果都用它一个图标 一句话 可选按钮通过 props 传文案、emit 触发按钮点击。Pinia 状态管理购物车 Storestores/cart.ts购物车状态需要在首页加购、购物车页管理、结算页读取之间共享。核心逻辑exportconstuseCartStoredefineStore(cart,(){constitemsrefCartItem[]([])// GettersisAllChecked 全选 / checkedCount 选中件数 / checkedTotal 选中总金额 / totalCount 角标数// ActionsfunctionaddItem(newItem){// 关键同商品 同规格合并数量否则新增一条constexistingitems.value.find(itemitem.product_idnewItem.product_idJSON.stringify(item.spec)JSON.stringify(newItem.spec))existing?existing.quantitynewItem.quantity:items.value.push({...newItem,checked:false})updateBadge()// 更新 TabBar 角标}functionremoveItem(productId){...}// 过滤掉指定商品 更新角标functionclearCart(){...}// 清空 更新角标},{persist:{key:meiyada-cart}})// 持久化杀掉小程序购物车还在用户 Storestores/user.ts管理登录状态、Token、个人信息exportconstuseUserStoredefineStore(user,(){consttokenref();constnicknameref();constavatarref()constisLoggedIncomputed(()!!token.value)asyncfunctionlogin(username,password){// 调后端登录接口拿 token → 存 state uni.setStorageSync(token)request.ts 自动读}functionlogout(){// 清空 state uni.removeStorageSync(token)}},{persist:{key:meiyada-user}})main.ts 注册 Piniaimport{createPinia}frompiniaimportpiniaPluginPersisteduniappfrompinia-plugin-persisted-uniappconstpiniacreatePinia()pinia.use(piniaPluginPersisteduniapp)// 挂持久化插件app.use(pinia)两个 Store 都用了持久化插件。购物车、Token 存在本地小程序杀掉再打开购物车的东西还在用户也不用重新登录。AI 加速让 AI 帮你写页面写前端页面最烦的是重复劳动——每个页面的结构都差不多就是数据和样式不一样。这种活让 AI 来“基于 uni-app Vue3 TypeScript生成一个电商商品列表页面。要求两列瀑布流布局每个卡片包含商品图片、名称、标签、价格、销量。使用 Composition API样式用 SCSS适配微信小程序。”AI 能给你生成 80% 的代码剩下 20% 是调整细节、对接接口。小程序的样式调试很痛苦——没有 Chrome DevTools 那么好用。遇到样式问题直接截图丢给 AI这个商品卡片的价格和标题重叠了帮我看看哪里出了问题。比自己一个个属性排查快多了。后端 API 文档给到 AI让它直接生成前端的接口调用代码也省得自己对着文档一行行翻译。学完来练练手 入门给商品卡片组件加一个限时折扣标签当商品有discount字段时显示倒计时 进阶给购物车页面加上左滑删除功能touchstart/touchmove/touchend监听手势 transform: translateX()实现滑动效果 挑战实现一个完整的搜索功能——搜索框输入 → 调用后端搜索接口 → 展示结果 → 支持历史记录本系列为梅雅达编程笔记原创首发于 CSDN。有问题评论区见