电商购物平台复盘
亮点1:商品模块:采用 “虚拟列表 + 分页加载” 方案,承载 10000 + 商品数据无卡顿;封装图片懒加载自
定义指令,有效减少页面初始加载的资源请求量,降低首屏渲染时间,优化大型页面的加载性能。
“虚拟列表 + 分页加载” 方案的实际应用
- 业务背景:生鲜商品品类繁多(水果、蔬菜、肉类等合计超 10000 种),传统列表渲染会一次性创建所有 DOM 元素,导致页面卡顿、滚动掉帧。
- 技术实现:
- 虚拟列表:使用
vue-virtual-scroller库,只渲染可视区域内的商品卡片(约 10-15 个),滚动时动态计算可视范围并复用 DOM 元素。
- 虚拟列表:使用
1 | <template> |
- 分页加载:配合后端接口实现分页,滚动到页面底部时触发加载下一页(页码 + 每页条数),同时将新数据追加到总数据池。
- 效果:10000 + 商品数据下,DOM 节点数量从原来的 10000 + 减少到 30 个以内,滚动帧率稳定在 60fps,滑动时无卡顿感。
图片懒加载自定义指令的封装与应用
业务痛点:生鲜商品图片多且清晰(单张约 200-500KB),首屏若加载全部图片会产生大量请求,导致首屏加载缓慢。
实现方案:封装
v-lazy自定义指令,基于IntersectionObserverAPI 监听图片是否进入视口,只加载可见区域图片。// 指令定义:directives/lazy.js export default { mounted(el, binding) { const observer = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { // 图片进入视口时加载 el.src = binding.value // 绑定的图片真实地址 observer.unobserve(el) // 加载后停止监听 } }) }) observer.observe(el) } }1. 实际业务场景:用户在购物车修改商品数量后,订单确认页会实时更新对应商品的数量和总价,无需手动刷新。 2. **购物车与订单数据同步误差率降至 0 的效果**未优化前,由于购物车和订单数据分散在组件中,常出现 “购物车已修改但订单页未更新” 的问题(误差率约 8%)。通过 Pinia 的集中管理和订阅机制: - 所有数据变更只有唯一入口(store 的 actions) - 关联模块自动同步更新 - 配合本地持久化,解决页面刷新导致的数据不一致 最终实现从购物车到订单提交的全流程数据零误差,用户提交订单时不会出现 “商品已下架但仍能下单” 等异常情况。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
- 应用场景:商品列表的缩略图、分类页的 banner 图均使用`v-lazy`指令,配合占位图(1KB 以内的灰色背景图)提升感知性能。
**亮点二: 基于 Pinia 实现 “状态 - 视图 - 操作” 解耦,拆分 8 个业务模块,通过订阅机制实现跨模块数据联**
**动,购物车与订单数据同步误差率降至 0**
1. **状态 - 视图 - 操作解耦的实现**
- **状态层**:用 Pinia 定义独立的 store(如 cartStore、orderStore),只负责数据存储和核心计算(例如 cartStore 中定义商品总数、总价的 getter)
- **视图层**:组件只通过 store 获取数据和调用方法(如购物车组件通过 cartStore.goodsList 渲染列表,点击删除按钮调用 cartStore.removeItem ())
- **操作层**:所有数据修改逻辑封装在 store 的 actions 中(如添加商品时的库存校验、价格计算等)
2. **8 个业务模块的拆分**按电商业务域拆分出:用户模块(userStore)、商品模块(goodsStore)、购物车模块(cartStore)、订单模块(orderStore)、地址模块(addressStore)、收藏模块(collectStore)、优惠券模块(couponStore)、全局设置模块(appStore)。每个模块只管理自身相关数据,例如 cartStore 仅维护购物车商品、选中状态等数据。
3. **跨模块数据联动的实际应用**通过 Pinia 的订阅机制($subscribe)实现模块间通信:
4. ```
// orderStore中订阅cartStore的变化
cartStore.$subscribe((mutation, state) => {
// 当购物车商品变化时,自动更新订单确认页的商品列表和总金额
if (mutation.type === 'cart/addItem') {
this.syncOrderGoods(state.goodsList)
}
})
亮点三:用户模块:用 vee-validate 实现表单校验,配合路由守卫实现 “未登录跳转拦截”,登录页安全性测试通过率 100%
vee-validate 表单校验的实际应用
针对登录页的手机号和密码字段,使用 vee-validate 定义了严格的校验规则:
// 手机号校验:必须为11位数字且符合手机号规则 defineRule('phone', (value) => { if (!value) return '请输入手机号' if (!/^1[3-9]\d{9}$/.test(value)) return '请输入正确的手机号' return true }) // 密码校验:8-20位,包含数字和字母 defineRule('password', (value) => { if (!value) return '请输入密码' if (value.length < 8 || value.length > 20) return '密码长度为8-20位' if (!/[0-9]/.test(value) || !/[a-zA-Z]/.test(value)) return '密码需包含数字和字母' })// 路由守卫配置 router.beforeEach((to, from, next) => { const isLogin = userStore.isLogin // 从Pinia获取登录状态 // 需要登录的路由在meta中标记requireAuth: true if (to.meta.requireAuth && !isLogin) { // 未登录时跳转到登录页,并记录当前页面路径(登录后可跳转回来) next({ path: '/login', query: { redirect: to.fullPath } }) } else { next() } })1
2
3
4
5
**路由守卫实现 “未登录跳转拦截”**
通过 Vue Router 的全局前置守卫,限制未登录用户访问需要权限的页面(如个人中心、订单页、结算页):- 实际效果:用户点击 “去结算” 按钮时,若未登录会自动跳转到登录页,登录成功后再返回结算页,既保证了权限安全,又不影响用户操作流程。

