前言
随着移动互联网的快速发展,电商应用已成为人们日常生活的重要组成部分。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开发技能,成功构建出自己的跨平台电商应用!

