前言
随着移动互联网的快速发展,电商应用已成为人们日常生活的重要组成部分。UniApp作为一款使用Vue.js开发所有前端应用的框架,让开发者能够通过编写一套代码,轻松发布到iOS、Android、Web以及各种小程序平台。本文将带领大家从零开始,开发一个功能完整的跨平台电商应用。
一、项目规划与技术选型
1.1 电商应用核心功能
一个完整的电商应用通常包含以下功能模块:
- 首页展示(轮播图、商品分类、推荐商品)
- 商品列表与搜索功能
- 商品详情页面
- 购物车管理
- 用户登录与注册
- 订单管理与支付集成
- 个人中心
1.2 技术栈选择
本项目将采用以下技术栈:
- 前端框架: UniApp + Vue.js
- UI组件库: uView UI
- 状态管理: Vuex
- 网络请求: uni.request 封装
- 数据持久化: uni.setStorageSync
- 支付集成: 微信支付、支付宝支付API
二、项目初始化与配置
2.1 创建UniApp项目
使用HBuilderX创建新项目:
选择项目类型: UniApp 模板: 默认模板 Vue版本: Vue 3 项目名称: UniMall
2.2 安装与配置uView UI
uView是UniApp生态中最优秀的UI框架之一,提供了丰富的组件:
# 通过npm安装 npm install uview-ui # 在main.js中引入 import uView from 'uview-ui' import { createApp } from 'vue' import App from './App' const app = createApp(App) app.use(uView) app.mount('#app') # 引入uView基础样式 @import 'uview-ui/theme.scss';
2.3 项目目录结构设计
uni-mall/ ├── components/ # 公共组件 │ ├── product-card/ # 商品卡片组件 │ ├── search-bar/ # 搜索栏组件 │ └── tab-bar/ # 底部导航组件 ├── pages/ # 页面目录 │ ├── index/ # 首页 │ ├── category/ # 分类页 │ ├── cart/ # 购物车 │ ├── user/ # 个人中心 │ └── product/ # 商品详情 ├── store/ # Vuex状态管理 │ ├── modules/ # 模块化store │ └── index.js # store入口 ├── api/ # 接口管理 ├── utils/ # 工具函数 ├── static/ # 静态资源 └── uni.scss # 全局样式
三、核心功能实现
3.1 首页设计与实现
首页是电商应用的门面,需要包含 banner轮播、分类导航和商品推荐等功能:
<template> <view class="home-container"> <!-- 搜索栏 --> <view class="search-area"> <u-search placeholder="搜索商品" v-model="keyword" :show-action="false" @click="goSearch" ></u-search> </view> <scroll-view scroll-y class="scroll-view"> <!-- 轮播图 --> <u-swiper :list="bannerList" keyName="image" height="300" @click="goBanner" ></u-swiper> <!-- 分类导航 --> <view class="category-section"> <view v-for="(item, index) in categoryList" :key="index" class="category-item" @click="goCategory(item.id)" > <image :src="item.icon" mode="aspectFit"></image> <text>{{ item.name }}</text> </view> </view> <!-- 推荐商品 --> <view class="recommend-section"> <view class="section-title"> <text>热门推荐</text> <text class="more" @click="goProductList">更多 ></text> </view> <view class="product-list"> <product-card v-for="product in recommendProducts" :key="product.id" :product="product" @click="goProductDetail(product.id)" ></product-card> </view> </view> </scroll-view> </view> </template>
3.2 商品详情页开发
商品详情页需要展示商品信息、规格选择、购买操作等:
<script> export default { data() { return { productId: '', productDetail: null, selectedSku: null, quantity: 1, showSkuPopup: false } }, onLoad(options) { this.productId = options.id this.loadProductDetail() }, methods: { async loadProductDetail() { try { const res = await this.$api.product.getDetail(this.productId) this.productDetail = res.data this.selectedSku = this.productDetail.skus[0] // 默认选择第一个SKU } catch (error) { uni.showToast({ title: '获取商品详情失败', icon: 'none' }) } }, // 选择规格 selectSku(sku) { this.selectedSku = sku this.showSkuPopup = false }, // 添加到购物车 async addToCart() { if (!this.selectedSku) { uni.showToast({ title: '请选择商品规格', icon: 'none' }) return } try { await this.$api.cart.addItem({ productId: this.productId, skuId: this.selectedSku.id, quantity: this.quantity }) uni.showToast({ title: '添加成功', icon: 'success' }) // 更新购物车数量 this.$store.dispatch('cart/updateCartCount') } catch (error) { uni.showToast({ title: '添加失败', icon: 'none' }) } }, // 立即购买 async buyNow() { if (!this.selectedSku) { uni.showToast({ title: '请选择商品规格', icon: 'none' }) return } try { const order = await this.$api.order.createDirect({ productId: this.productId, skuId: this.selectedSku.id, quantity: this.quantity }) // 跳转到订单确认页 uni.navigateTo({ url: `/pages/order/confirm?orderId=${order.id}` }) } catch (error) { uni.showToast({ title: '创建订单失败', icon: 'none' }) } } } } </script>
3.3 购物车功能实现
购物车需要支持商品增删改查、全选/反选和价格计算:
// store/modules/cart.js export default { namespaced: true, state: { items: [], selectedItems: [] }, getters: { // 计算总价 totalPrice(state) { return state.selectedItems.reduce((total, item) => { return total + (item.price * item.quantity) }, 0) }, // 是否全选 isAllSelected(state) { if (state.items.length === 0) return false return state.items.every(item => item.selected) } }, mutations: { SET_CART_ITEMS(state, items) { state.items = items }, TOGGLE_ITEM_SELECTION(state, itemId) { const item = state.items.find(item => item.id === itemId) if (item) { item.selected = !item.selected } }, UPDATE_ITEM_QUANTITY(state, { itemId, quantity }) { const item = state.items.find(item => item.id === itemId) if (item) { item.quantity = quantity } }, // 全选/反选 TOGGLE_ALL_SELECTION(state) { const allSelected = state.items.every(item => item.selected) state.items.forEach(item => { item.selected = !allSelected }) } }, actions: { async loadCartItems({ commit }) { try { const res = await uni.$api.cart.getList() commit('SET_CART_ITEMS', res.data) } catch (error) { console.error('加载购物车失败', error) } }, async updateCartCount({ dispatch }) { // 更新购物车角标 const res = await uni.$api.cart.getCount() uni.setTabBarBadge({ index: 2, text: res.data > 0 ? res.data.toString() : '' }) } } }
四、支付功能集成
4.1 微信支付集成
UniApp提供了统一的支付API,可以轻松集成多平台支付功能:
// utils/payment.js export const payOrder = async (orderId) => { try { // 获取支付参数 const paymentParams = await uni.$api.order.getPaymentParams(orderId) // 调用支付接口 const [err, res] = await uni.requestPayment({ provider: 'wxpay', orderInfo: paymentParams, // 微信支付参数 timeStamp: paymentParams.timeStamp, nonceStr: paymentParams.nonceStr, package: paymentParams.package, signType: paymentParams.signType, paySign: paymentParams.paySign }) if (err) { // 支付失败 uni.showToast({ title: '支付取消', icon: 'none' }) return false } // 支付成功 uni.showToast({ title: '支付成功', icon: 'success' }) // 更新订单状态 await uni.$api.order.updateStatus(orderId, 'paid') return true } catch (error) { console.error('支付失败', error) uni.showToast({ title: '支付失败', icon: 'none' }) return false } }
4.2 多平台支付适配
针对不同平台使用条件编译实现支付适配:
// 支付方法适配 export const unifiedPay = async (orderId) => { // #ifdef MP-WEIXIN return await wechatPay(orderId) // #endif // #ifdef APP-PLUS return await appPay(orderId) // #endif // #ifdef H5 return await h5Pay(orderId) // #endif } // 微信小程序支付 const wechatPay = async (orderId) => { // 微信小程序支付逻辑 } // App支付(同时处理iOS和Android) const appPay = async (orderId) => { // 获取支付参数 const paymentParams = await uni.$api.order.getAppPaymentParams(orderId) // 根据平台调用不同支付 // #ifdef APP-PLUS if (plus.os.name === 'iOS') { // iOS支付逻辑 } else { // Android支付逻辑 } // #endif } // H5支付(通常跳转到支付页面) const h5Pay = async (orderId) => { const paymentUrl = await uni.$api.order.getH5PaymentUrl(orderId) uni.navigateTo({ url: `/pages/webview/webview?url=${encodeURIComponent(paymentUrl)}` }) }
五、性能优化与最佳实践
5.1 图片懒加载与优化
电商应用图片资源较多,需要优化加载性能:
// 使用UniApp自带的懒加载 <image lazy-load :src="item.image" mode="aspectFill" class="product-image" ></image> // 使用WebP格式图片(条件编译) <image :src="getImageUrl(item.image)" mode="aspectFill" ></image> // 工具函数 export const getImageUrl = (url) => { // #ifdef APP-PLUS || H5 // APP和H5平台使用WebP格式 if (url && !url.includes('?') && supportsWebP()) { return `${url}?format=webp` } // #endif return url } // 检测WebP支持 export const supportsWebP = () => { const canvas = document.createElement('canvas') if (canvas.getContext && canvas.getContext('2d')) { return canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0 } return false }
5.2 数据缓存策略
合理使用缓存减少网络请求,提升用户体验:
// utils/cache.js const CACHE_PREFIX = 'uni_mall_' export const cache = { // 设置缓存 set(key, data, expire = 3600) { const cacheData = { data, expire: Date.now() + expire * 1000 } try { uni.setStorageSync(CACHE_PREFIX + key, cacheData) } catch (e) { console.error('缓存设置失败', e) } }, // 获取缓存 get(key) { try { const cacheData = uni.getStorageSync(CACHE_PREFIX + key) if (!cacheData) return null // 检查是否过期 if (Date.now() > cacheData.expire) { this.remove(key) return null } return cacheData.data } catch (e) { console.error('缓存获取失败', e) return null } }, // 删除缓存 remove(key) { try { uni.removeStorageSync(CACHE_PREFIX + key) } catch (e) { console.error('缓存删除失败', e) } } } // 在API调用中使用缓存 export const getHomeData = async (useCache = true) => { const cacheKey = 'home_data' // 尝试从缓存获取 if (useCache) { const cachedData = cache.get(cacheKey) if (cachedData) { return cachedData } } // 从网络获取 try { const res = await uni.$api.home.getData() // 缓存数据(5分钟) cache.set(cacheKey, res.data, 300) return res.data } catch (error) { throw error } }
5.3 组件按需加载与分包优化
通过分包和组件懒加载优化首屏加载速度:
// pages.json 配置分包 { "pages": [ // 主包页面 { "path": "pages/index/index", "style": { ... } } ], "subPackages": [ { "root": "pages/product", "pages": [ { "path": "detail", "style": { ... } }, { "path": "list", "style": { ... } } ] }, { "root": "pages/user", "pages": [ { "path": "center", "style": { ... } }, { "path": "order/list", "style": { ... } } ] } ], "preloadRule": { "pages/index/index": { "network": "all", "packages": ["pages/product"] } } } // 组件懒加载 const ProductDetail = () => import('@/pages/product/detail.vue') const OrderConfirm = () => import('@/pages/order/confirm.vue')
六、多端适配与发布
6.1 平台差异处理
使用条件编译处理不同平台的差异:
// 导航栏适配 const getNavBarHeight = () => { // #ifdef MP-WEIXIN const { statusBarHeight, platform } = wx.getSystemInfoSync() const { height, top } = wx.getMenuButtonBoundingClientRect() return (top - statusBarHeight) * 2 + height + statusBarHeight // #endif // #ifdef H5 return 44 // #endif // #ifdef APP-PLUS return 44 // #endif } // 安全区域适配 .safe-area-inset-bottom { padding-bottom: constant(safe-area-inset-bottom); padding-bottom: env(safe-area-inset-bottom); }
6.2 应用发布流程
不同平台的发布准备工作:
- 微信小程序: 配置appid、上传代码、提交审核
- App: 生成证书、配置应用图标和启动图、云打包
- H5: 配置部署服务器、设置路由模式、优化SEO
发布前的检查清单:
- 测试所有核心功能在不同平台的兼容性
- 优化应用性能,减少首屏加载时间
- 确保支付流程完整可用
- 添加必要的权限申请和隐私政策提示
- 配置应用更新机制
结语
通过本教程,我们完整地实现了一个跨平台电商应用的核心功能。UniApp的强大之处在于其”一次开发,多端发布”的能力,极大地提高了开发效率。在实际项目中,还需要根据业务需求不断完善细节,如增加会员系统、优惠券、积分等功能。
开发过程中要注意性能优化和多端适配,确保在不同平台上都能提供良好的用户体验。同时,随着UniApp生态的不断发展,建议持续关注官方更新和社区最佳实践,以便采用更先进的技术方案。
希望本教程能够帮助你快速掌握UniApp开发技能,成功构建出自己的跨平台电商应用!