Skip to content

5-1 实战项目:移动端商品小应用

恭喜你走到这里!这一章把前面学的全部串起来,做一个真实的 H5 移动端商品应用:商品列表 → 商品详情 → 购物车,带下拉刷新、上拉加载、底部导航、状态持久化。

配套完整项目:05-实战项目/shop-app/,装好依赖即可运行。


1. 项目用到了哪些知识

功能用到的知识(章节)
单文件组件 + <script setup>2-1
页面跳转(列表→详情→购物车)Vue Router(2-2)
购物车跨页共享 + 持久化Pinia(2-3)
取商品数据api 封装思路(2-4,这里用本地 mock 便于离线运行)
移动端适配vw + postcss 插件(3-1)
UI 组件(NavBar/Card/Tabbar/Stepper...)Vant(3-2)
下拉刷新 + 上拉加载van-pull-refresh / van-list(3-3)

为了离线也能跑,商品数据用本地 mock(src/api/)模拟接口(返回 Promise,带延迟,像真实请求)。换成真后端时,把 mock 换成 2-4 的 axios 调用即可,组件代码不用动——这正是把接口收拢到 api/ 层的好处。


2. 怎么跑起来

bash
cd 05-实战项目/shop-app
npm install
npm run dev

浏览器打开后,按 F12 → 点设备工具栏图标,切到手机视图(如 iPhone SE / 12),体验最佳。


3. 项目结构与数据流

shop-app/src/
├── main.js              ← 入口:装 Pinia / Router / Vant
├── App.vue              ← 根:<router-view> + 底部 Tabbar
├── router/index.js      ← 路由:列表 / 详情 / 购物车 / 我的
├── stores/cart.js       ← 购物车 Pinia store(含 localStorage 持久化)
├── api/
│   ├── mock.js          ← 模拟商品数据
│   └── product.js       ← getProductPage / getProduct(返回 Promise)
└── views/
    ├── ProductList.vue  ← 商品列表(下拉刷新 + 上拉分页加载)
    ├── ProductDetail.vue← 商品详情(加入购物车)
    ├── Cart.vue         ← 购物车(改数量 / 删除 / 结算)
    └── Mine.vue         ← 我的(展示购物车统计)

数据流核心:购物车数据放在 Pinia 的 cart store 里。

列表页/详情页  ──cart.add(商品)──►  cart store(全局)

       底部 Tabbar 角标 ◄──totalCount──┤
       购物车页 ◄────items / 增删改─────┘

三个页面都操作同一个 store,互不直接通信——这就是 2-3 讲的全局状态管理在实战里的样子。


4. 关键代码讲解

(1)购物车 store(stores/cart.js)

js
export const useCartStore = defineStore('cart', () => {
  // 初始化时从 localStorage 读,实现刷新不丢(2-3 提到的持久化)
  const items = ref(JSON.parse(localStorage.getItem('cart') || '[]'))

  const totalCount = computed(() => items.value.reduce((s, i) => s + i.qty, 0))
  const totalPrice = computed(() => items.value.reduce((s, i) => s + i.price * i.qty, 0))

  function add(p) {
    const found = items.value.find(i => i.id === p.id)
    if (found) found.qty++              // 已有就加数量
    else items.value.push({ id: p.id, name: p.name, price: p.price, emoji: p.emoji, qty: 1 })
  }
  function setQty(id, qty) { const f = items.value.find(i => i.id === id); if (f) f.qty = qty }
  function remove(id) { items.value = items.value.filter(i => i.id !== id) }
  function clear() { items.value = [] }

  // 监听变化,自动存回 localStorage(watch 的副作用,1-3)
  watch(items, (v) => localStorage.setItem('cart', JSON.stringify(v)), { deep: true })

  return { items, totalCount, totalPrice, add, setQty, remove, clear }
})

把 1-3(computed/watch)、2-3(Pinia)、持久化全用上了。

(2)列表页:下拉刷新 + 上拉加载(ProductList.vue)

vue
<van-pull-refresh v-model="refreshing" @refresh="onRefresh">
  <van-list v-model:loading="loading" :finished="finished"
            finished-text="没有更多了" @load="onLoad">
    <!-- 商品卡片 v-for ... -->
  </van-list>
</van-pull-refresh>
js
let page = 1
async function onLoad() {                 // 滚到底自动触发
  const res = await getProductPage(page)
  if (refreshing.value) refreshing.value = false
  list.value.push(...res.items)           // 追加
  loading.value = false
  if (res.hasMore) page++
  else finished.value = true
}
function onRefresh() {                     // 下拉触发
  finished.value = false; page = 1; list.value = []
  loading.value = true; onLoad()           // 从头加载
}

这就是 3-3 那套「分页 + 三状态」的真实落地。

(3)路由与底部导航

App.vue<van-tabbar route> 配合 vue-router:点 Tab 自动切路由,角标读 Pinia 的 totalCount。详情页通过 meta.hideTab 隐藏底部栏(沉浸式)。


5. 建议的学习路径(动手!)

别只看,一定要动手改。推荐按顺序做这几个练习,做完你就真的掌握了:

  1. 加商品:在 api/mock.js 加一个新商品(照已有格式),刷新看列表多一个。
  2. 改详情:在 ProductDetail.vue 给详情页加一个「库存:xx」显示(mock 里加 stock 字段)。
  3. 购物车数量:在 Cart.vue 体会 van-stepper 改数量,看合计金额实时变(computed)。
  4. 持久化验证:加几件商品到购物车,刷新页面,发现购物车还在(localStorage 持久化)。
  5. 接真后端(进阶):把 api/product.js 里的 mock 换成 2-4 的 axios 写法,指向你们后端的商品接口——你会发现页面组件几乎不用改。
  6. 加搜索(进阶):列表页顶部加 van-search,根据关键字过滤商品(用 computed 过滤)。

6. 你已经具备的能力

走完这套教程,你现在能:

  • ✅ 看懂并写 Vue 3 组件(响应式、指令、组件通信、生命周期)
  • ✅ 用 Vite 工程化开发,配路由、状态管理、调接口
  • ✅ 做 H5 移动端适配,用 Vant 快速搭界面
  • ✅ 实现列表、详情、购物车这类真实业务页面
  • ✅ 看懂公司项目的代码结构,参与实际开发

7. 接下来往哪走

  • 多读公司项目代码:对照本教程的结构(router/stores/api/views/components),很快能上手。
  • 遇到不会的组件查 Vant 文档,遇到不会的语法查 Vue 官方文档。
  • 补 TypeScript(第 4 部分):如果公司项目用 TS,把组件逐步加上类型。
  • 进阶主题(用到再学):权限路由守卫、请求 loading 全局拦截、组件库主题定制、性能优化、单元测试。

后端转前端最难的是「思维转变」——从「掌控流程」到「维护状态、响应事件」。你已经迈过这道坎了。剩下的就是在真实项目里多写多练。加油!🚀

🎉 全部教程完成! 回到 总目录 README 可随时复习任意章节。

写给有后端基础、想系统学习 Vue 3 与 H5 的开发者