电商应用实战
电商应用是 uni-app 最常见的应用场景之一,本文将介绍如何使用 uni-app 开发一个功能完善的电商应用。
应用架构
一个典型的电商应用通常包含以下核心模块:
- 首页:展示推荐商品、活动banner、分类入口等
- 分类:商品分类展示
- 商品详情:展示商品信息、规格选择、评价等
- 购物车:管理待购商品
- 订单:订单创建、支付、物流跟踪等
- 个人中心:用户信息、收货地址、优惠券等
- 搜索:商品搜索功能
技术选型
前端技术
- uni-app:跨平台开发框架
- Vue.js:响应式数据绑定
- Vuex:状态管理
- uni-ui:UI组件库
后端服务
- 云函数:处理业务逻辑
- 云数据库:存储商品、用户、订单等数据
- 云存储:存储商品图片等资源
- 支付接口:对接各平台支付功能
项目结构
├── components // 自定义组件
│ ├── goods-card // 商品卡片组件
│ ├── price // 价格组件
│ └── rating // 评分组件
├── pages // 页面文件夹
│ ├── index // 首页
│ ├── category // 分类页
│ ├── goods-detail // 商品详情页
│ ├── cart // 购物车
│ ├── order // 订单相关页面
│ └── user // 用户中心
├── static // 静态资源
├── store // Vuex 状态管理
│ ├── index.js // 组装模块并导出
│ ├── cart.js // 购物车状态
│ └── user.js // 用户状态
├── utils // 工具函数
│ ├── request.js // 请求封装
│ └── payment.js // 支付相关
├── App.vue // 应用入口
├── main.js // 主入口
├── manifest.json // 配置文件
└── pages.json // 页面配置
核心功能实现
1. 商品列表与筛选
商品列表是电商应用的基础功能,支持分类筛选、价格排序、销量排序等功能。
vue
<template>
<view class="goods-list">
<!-- 筛选栏 -->
<view class="filter-bar">
<view
class="filter-item"
:class="{ active: sortType === 'default' }"
@click="changeSort('default')"
>综合</view>
<view
class="filter-item"
:class="{ active: sortType === 'sales' }"
@click="changeSort('sales')"
>销量</view>
<view
class="filter-item"
:class="{ active: sortType === 'price' }"
@click="changeSort('price')"
>
价格
<text class="sort-icon">{{ sortOrder === 'asc' ? '↑' : '↓' }}</text>
</view>
</view>
<!-- 商品列表 -->
<view class="goods-container">
<goods-card
v-for="item in goodsList"
:key="item.id"
:goods="item"
@click="navigateToDetail(item.id)"
></goods-card>
</view>
<!-- 加载更多 -->
<uni-load-more :status="loadMoreStatus"></uni-load-more>
</view>
</template>
<script>
import goodsCard from '@/components/goods-card/goods-card.vue';
import uniLoadMore from '@/components/uni-load-more/uni-load-more.vue';
export default {
components: {
goodsCard,
uniLoadMore
},
data() {
return {
goodsList: [],
categoryId: '',
keyword: '',
page: 1,
pageSize: 10,
sortType: 'default', // default, sales, price
sortOrder: 'desc', // asc, desc
loadMoreStatus: 'more' // more, loading, noMore
}
},
onLoad(options) {
if (options.categoryId) {
this.categoryId = options.categoryId;
}
if (options.keyword) {
this.keyword = options.keyword;
}
this.loadGoodsList();
},
onReachBottom() {
if (this.loadMoreStatus !== 'noMore') {
this.page++;
this.loadGoodsList();
}
},
methods: {
// 加载商品列表
async loadGoodsList() {
this.loadMoreStatus = 'loading';
try {
const params = {
page: this.page,
pageSize: this.pageSize,
sortType: this.sortType,
sortOrder: this.sortOrder,
categoryId: this.categoryId || undefined,
keyword: this.keyword || undefined
};
const res = await this.$api.goods.list(params);
if (this.page === 1) {
this.goodsList = res.data.list;
} else {
this.goodsList = [...this.goodsList, ...res.data.list];
}
this.loadMoreStatus = res.data.list.length < this.pageSize ? 'noMore' : 'more';
} catch (e) {
console.error(e);
this.loadMoreStatus = 'more';
uni.showToast({
title: '加载失败',
icon: 'none'
});
}
},
// 切换排序方式
changeSort(type) {
if (this.sortType === type) {
// 同一排序类型,切换排序顺序
if (type === 'price') {
this.sortOrder = this.sortOrder === 'asc' ? 'desc' : 'asc';
}
} else {
// 不同排序类型,设置默认排序顺序
this.sortType = type;
this.sortOrder = type === 'price' ? 'asc' : 'desc';
}
// 重新加载数据
this.page = 1;
this.loadGoodsList();
},
// 跳转到商品详情
navigateToDetail(goodsId) {
uni.navigateTo({
url: `/pages/goods-detail/goods-detail?id=${goodsId}`
});
}
}
}
</script>
2. 商品详情页
商品详情页是用户了解商品信息、选择规格并下单的关键页面。
vue
<template>
<view class="goods-detail">
<!-- 轮播图 -->
<swiper class="swiper" indicator-dots autoplay circular>
<swiper-item v-for="(item, index) in goods.images" :key="index">
<image :src="item" mode="aspectFill" class="slide-image"></image>
</swiper-item>
</swiper>
<!-- 商品信息 -->
<view class="goods-info">
<view class="price-box">
<price :value="goods.price"></price>
<text class="original-price" v-if="goods.originalPrice">¥{{goods.originalPrice}}</text>
</view>
<view class="title">{{goods.title}}</view>
<view class="sub-title">{{goods.subtitle}}</view>
</view>
<!-- 规格选择 -->
<view class="spec-section" @click="openSpecModal">
<text class="section-title">选择</text>
<text class="selected-text">{{selectedSpecText}}</text>
<text class="arrow">></text>
</view>
<!-- 商品详情 -->
<view class="detail-section">
<view class="section-header">
<text class="section-title">商品详情</text>
</view>
<rich-text :nodes="goods.detail"></rich-text>
</view>
<!-- 底部操作栏 -->
<view class="footer">
<view class="icon-btn">
<text class="iconfont icon-home"></text>
<text>首页</text>
</view>
<view class="icon-btn">
<text class="iconfont icon-cart"></text>
<text>购物车</text>
<text class="badge" v-if="cartCount > 0">{{cartCount}}</text>
</view>
<button class="action-btn btn-cart" @click="addToCart">加入购物车</button>
<button class="action-btn btn-buy" @click="buyNow">立即购买</button>
</view>
<!-- 规格选择弹窗 -->
<uni-popup ref="specPopup" type="bottom">
<view class="spec-popup">
<view class="spec-header">
<image :src="goods.thumbnail" class="goods-thumb"></image>
<view class="spec-info">
<price :value="selectedSkuPrice || goods.price"></price>
<text class="stock">库存 {{selectedSkuStock || goods.stock}} 件</text>
<text class="selected">已选:{{selectedSpecText}}</text>
</view>
<text class="close-btn" @click="closeSpecModal">×</text>
</view>
<scroll-view scroll-y class="spec-content">
<view
class="spec-group"
v-for="(group, groupIndex) in goods.specs"
:key="groupIndex"
>
<text class="spec-group-title">{{group.name}}</text>
<view class="spec-items">
<text
class="spec-item"
:class="{ active: isSpecSelected(groupIndex, valueIndex) }"
v-for="(value, valueIndex) in group.values"
:key="valueIndex"
@click="selectSpec(groupIndex, valueIndex)"
>{{value}}</text>
</view>
</view>
<view class="quantity-box">
<text class="quantity-label">数量</text>
<uni-number-box
:min="1"
:max="selectedSkuStock || goods.stock"
v-model="quantity"
></uni-number-box>
</view>
</scroll-view>
<view class="spec-footer">
<button class="btn-confirm-cart" @click="confirmAddToCart">加入购物车</button>
<button class="btn-confirm-buy" @click="confirmBuyNow">立即购买</button>
</view>
</view>
</uni-popup>
</view>
</template>
<script>
import price from '@/components/price/price.vue';
import uniPopup from '@/components/uni-popup/uni-popup.vue';
import uniNumberBox from '@/components/uni-number-box/uni-number-box.vue';
import { mapGetters, mapActions } from 'vuex';
export default {
components: {
price,
uniPopup,
uniNumberBox
},
data() {
return {
goodsId: '',
goods: {
id: '',
title: '',
subtitle: '',
price: 0,
originalPrice: 0,
stock: 0,
thumbnail: '',
images: [],
detail: '',
specs: [],
skus: []
},
selectedSpecs: [],
quantity: 1,
buyType: '' // cart, buy
}
},
computed: {
...mapGetters('cart', ['cartCount']),
// 已选规格文本
selectedSpecText() {
if (!this.goods.specs || this.goods.specs.length === 0) {
return '默认';
}
if (this.selectedSpecs.length === 0) {
return '请选择规格';
}
let text = [];
this.goods.specs.forEach((group, index) => {
if (this.selectedSpecs[index] !== undefined) {
text.push(group.values[this.selectedSpecs[index]]);
}
});
return text.join(',');
},
// 选中的SKU价格
selectedSkuPrice() {
const sku = this.getSelectedSku();
return sku ? sku.price : null;
},
// 选中的SKU库存
selectedSkuStock() {
const sku = this.getSelectedSku();
return sku ? sku.stock : null;
}
},
onLoad(options) {
this.goodsId = options.id;
this.loadGoodsDetail();
},
methods: {
...mapActions('cart', ['addCart']),
// 加载商品详情
async loadGoodsDetail() {
try {
const res = await this.$api.goods.detail({
id: this.goodsId
});
this.goods = res.data;
// 初始化选中规格数组
if (this.goods.specs && this.goods.specs.length > 0) {
this.selectedSpecs = new Array(this.goods.specs.length).fill(undefined);
}
} catch (e) {
console.error(e);
uni.showToast({
title: '加载失败',
icon: 'none'
});
}
},
// 打开规格选择弹窗
openSpecModal() {
this.$refs.specPopup.open();
},
// 关闭规格选择弹窗
closeSpecModal() {
this.$refs.specPopup.close();
},
// 判断规格是否选中
isSpecSelected(groupIndex, valueIndex) {
return this.selectedSpecs[groupIndex] === valueIndex;
},
// 选择规格
selectSpec(groupIndex, valueIndex) {
this.$set(this.selectedSpecs, groupIndex, valueIndex);
},
// 获取选中的SKU
getSelectedSku() {
// 如果没有规格或者规格未选择完整,返回null
if (!this.goods.specs || this.goods.specs.length === 0 ||
this.selectedSpecs.includes(undefined)) {
return null;
}
// 根据选中的规格查找对应的SKU
const selectedSpecValues = this.selectedSpecs.map((valueIndex, groupIndex) => {
return this.goods.specs[groupIndex].values[valueIndex];
});
return this.goods.skus.find(sku => {
return JSON.stringify(sku.specs) === JSON.stringify(selectedSpecValues);
});
},
// 加入购物车按钮点击
addToCart() {
this.buyType = 'cart';
this.openSpecModal();
},
// 立即购买按钮点击
buyNow() {
this.buyType = 'buy';
this.openSpecModal();
},
// 确认加入购物车
async confirmAddToCart() {
// 检查规格是否选择完整
if (this.goods.specs && this.goods.specs.length > 0 &&
this.selectedSpecs.includes(undefined)) {
uni.showToast({
title: '请选择完整规格',
icon: 'none'
});
return;
}
// 获取选中的SKU
const sku = this.getSelectedSku();
// 构建购物车商品对象
const cartItem = {
goodsId: this.goods.id,
skuId: sku ? sku.id : null,
title: this.goods.title,
price: sku ? sku.price : this.goods.price,
image: this.goods.thumbnail,
specs: this.selectedSpecText,
quantity: this.quantity
};
// 添加到购物车
try {
await this.addCart(cartItem);
uni.showToast({
title: '已加入购物车',
icon: 'success'
});
this.closeSpecModal();
} catch (e) {
uni.showToast({
title: '添加失败',
icon: 'none'
});
}
},
// 确认立即购买
confirmBuyNow() {
// 检查规格是否选择完整
if (this.goods.specs && this.goods.specs.length > 0 &&
this.selectedSpecs.includes(undefined)) {
uni.showToast({
title: '请选择完整规格',
icon: 'none'
});
return;
}
// 获取选中的SKU
const sku = this.getSelectedSku();
// 构建订单商品对象
const orderItem = {
goodsId: this.goods.id,
skuId: sku ? sku.id : null,
title: this.goods.title,
price: sku ? sku.price : this.goods.price,
image: this.goods.thumbnail,
specs: this.selectedSpecText,
quantity: this.quantity
};
// 跳转到订单确认页
uni.navigateTo({
url: '/pages/order/confirm/confirm',
success: (res) => {
res.eventChannel.emit('orderData', {
items: [orderItem],
from: 'buyNow'
});
}
});
this.closeSpecModal();
}
}
}
</script>
3. 购物车功能
购物车是电商应用的核心功能之一,支持商品的添加、删除、修改数量等操作。
vue
<template>
<view class="cart-page">
<!-- 空购物车提示 -->
<view class="empty-cart" v-if="cartList.length === 0">
<image src="/static/images/empty-cart.png" class="empty-image"></image>
<text class="empty-text">购物车还是空的</text>
<button class="go-shopping-btn" @click="goShopping">去逛逛</button>
</view>
<!-- 购物车列表 -->
<block v-else>
<view class="cart-list">
<view
class="cart-item"
v-for="(item, index) in cartList"
:key="item.id"
>
<view class="checkbox">
<checkbox
:checked="item.selected"
@click="toggleSelect(index)"
color="#ff6700"
></checkbox>
</view>
<image :src="item.image" class="goods-image" mode="aspectFill"></image>
<view class="goods-info">
<text class="goods-title">{{item.title}}</text>
<text class="goods-specs">{{item.specs}}</text>
<view class="price-quantity">
<price :value="item.price"></price>
<uni-number-box
:value="item.quantity"
:min="1"
@change="(value) => updateQuantity(index, value)"
></uni-number-box>
</view>
</view>
<text class="delete-btn" @click="removeCartItem(index)">×</text>
</view>
</view>
<!-- 底部结算栏 -->
<view class="cart-footer">
<view class="select-all">
<checkbox
:checked="isAllSelected"
@click="toggleSelectAll"
color="#ff6700"
></checkbox>
<text>全选</text>
</view>
<view class="total-info">
<text>合计:</text>
<price :value="totalPrice" size="32"></price>
</view>
<button
class="checkout-btn"
:disabled="selectedCount === 0"
@click="checkout"
>结算({{selectedCount}})</button>
</view>
</block>
</view>
</template>
<script>
import price from '@/components/price/price.vue';
import uniNumberBox from '@/components/uni-number-box/uni-number-box.vue';
import { mapState, mapGetters, mapMutations, mapActions } from 'vuex';
export default {
components: {
price,
uniNumberBox
},
computed: {
...mapState('cart', ['cartList']),
...mapGetters('cart', ['totalPrice', 'selectedCount', 'isAllSelected']),
},
methods: {
...mapMutations('cart', ['updateCartItem', 'removeFromCart', 'toggleSelectItem', 'toggleSelectAll']),
...mapActions('cart', ['checkout']),
// 切换选中状态
toggleSelect(index) {
this.toggleSelectItem(index);
},
// 更新商品数量
updateQuantity(index, value) {
this.updateCartItem({
index,
quantity: value
});
},
// 删除购物车商品
removeCartItem(index) {
uni.showModal({
title: '提示',
content: '确定要删除该商品吗?',
success: (res) => {
if (res.confirm) {
this.removeFromCart(index);
}
}
});
},
// 去购物
goShopping() {
uni.switchTab({
url: '/pages/index/index'
});
},
// 结算
checkout() {
if (this.selectedCount === 0) {
return;
}
uni.navigateTo({
url: '/pages/order/confirm/confirm',
success: (res) => {
res.eventChannel.emit('orderData', {
from: 'cart'
});
}
});
}
}
}
</script>
4. 订单确认与支付
订单确认页面用于确认订单信息、选择收货地址和支付方式等。
vue
<template>
<view class="order-confirm">
<!-- 收货地址 -->
<view class="address-section" @click="chooseAddress">
<view class="address-info" v-if="address">
<view class="user-info">
<text class="name">{{address.name}}</text>
<text class="phone">{{address.phone}}</text>
</view>
<view class="address-detail">{{address.province}}{{address.city}}{{address.district}}{{address.detail}}</view>
</view>
<view class="no-address" v-else>
<text>请选择收货地址</text>
</view>
<text class="iconfont icon-right"></text>
</view>
<!-- 商品列表 -->
<view class="goods-section">
<view class="section-title">商品信息</view>
<view
class="goods-item"
v-for="(item, index) in orderItems"
:key="index"
>
<image :src="item.image" class="goods-image" mode="aspectFill"></image>
<view class="goods-info">
<text class="goods-title">{{item.title}}</text>
<text class="goods-specs">{{item.specs}}</text>
</view>
<view class="goods-price">
<price :value="item.price"></price>
<text class="goods-quantity">x{{item.quantity}}</text>
</view>
</view>
</view>
<!-- 配送方式 -->
<view class="delivery-section">
<view class="section-item">
<text class="item-label">配送方式</text>
<view class="item-value">
<text>快递配送</text>
</view>
</view>
</view>
<!-- 优惠券 -->
<view class="coupon-section" @click="chooseCoupon">
<view class="section-item">
<text class="item-label">优惠券</text>
<view class="item-value">
<text v-if="selectedCoupon">-¥{{selectedCoupon.amount}}</text>
<text v-else>{{availableCoupons.length > 0 ? `${availableCoupons.length}张可用` : '无可用优惠券'}}</text>
<text class="iconfont icon-right"></text>
</view>
</view>
</view>
<!-- 订单金额 -->
<view class="amount-section">
<view class="section-item">
<text class="item-label">商品金额</text>
<view class="item-value">
<price :value="goodsAmount"></price>
</view>
</view>
<view class="section-item">
<text class="item-label">运费</text>
<view class="item-value">
<price :value="deliveryFee"></price>
</view>
</view>
<view class="section-item" v-if="selectedCoupon">
<text class="item-label">优惠券</text>
<view class="item-value coupon-value">
<price :value="-selectedCoupon.amount"></price>
</view>
</view>
</view>
<!-- 备注 -->
<view class="remark-section">
<text class="remark-label">备注</text>
<input
type="text"
v-model="remark"
placeholder="选填,请先和商家协商一致"
class="remark-input"
/>
</view>
<!-- 底部结算栏 -->
<view class="footer">
<view class="total-info">
<text>合计:</text>
<price :value="totalAmount" size="36" color="#ff6700"></price>
</view>
<button class="submit-btn" @click="submitOrder">提交订单</button>
</view>
</view>
</template>
<script>
import price from '@/components/price/price.vue';
import { mapState, mapActions } from 'vuex';
export default {
components: {
price
},
data() {
return {
orderItems: [],
address: null,
selectedCoupon: null,
remark: '',
orderSource: '', // cart, buyNow
deliveryFee: 0
}
},
computed: {
...mapState('user', ['addressList', 'availableCoupons']),
// 商品总金额
goodsAmount() {
return this.orderItems.reduce((total, item) => {
return total + item.price * item.quantity;
}, 0);
},
// 订单总金额
totalAmount() {
let amount = this.goodsAmount + this.deliveryFee;
if (this.selectedCoupon) {
amount -= this.selectedCoupon.amount;
}
return amount > 0 ? amount : 0;
}
},
methods: {
// 计算运费
calculateDeliveryFee() {
// 根据商品总价和收货地址计算运费
if (this.goodsAmount >= 99) {
this.deliveryFee = 0; // 满99包邮
} else {
this.deliveryFee = 10; // 默认运费10元
}
},
// 提交订单
async submitOrder() {
// 验证收货地址
if (!this.address) {
uni.showToast({
title: '请选择收货地址',
icon: 'none'
});
return;
}
// 构建订单数据
const orderData = {
addressId: this.address.id,
items: this.orderItems,
couponId: this.selectedCoupon ? this.selectedCoupon.id : null,
remark: this.remark,
deliveryFee: this.deliveryFee,
totalAmount: this.totalAmount
};
try {
// 创建订单
const result = await this.createOrder(orderData);
// 跳转到支付页面
uni.navigateTo({
url: `/pages/order/payment/payment?orderId=${result.orderId}&amount=${this.totalAmount}`
});
} catch (e) {
uni.showToast({
title: '创建订单失败',
icon: 'none'
});
}
}
}
}
</script>
5. 个人中心
个人中心页面展示用户信息和各种功能入口,如订单管理、收货地址、优惠券等。
vue
<template>
<view class="user-center">
<!-- 用户信息 -->
<view class="user-info-section">
<view class="user-info" @click="goToUserInfo">
<image :src="userInfo.avatar || '/static/images/default-avatar.png'" class="avatar"></image>
<view class="info">
<text class="nickname">{{userInfo.nickname || '未登录'}}</text>
<text class="member-level" v-if="userInfo.id">{{userInfo.memberLevel}}</text>
</view>
</view>
<view class="user-assets">
<view class="asset-item" @click="goToWallet">
<text class="asset-value">{{userInfo.balance || 0}}</text>
<text class="asset-label">余额</text>
</view>
<view class="asset-item" @click="goToCoupon">
<text class="asset-value">{{userInfo.couponCount || 0}}</text>
<text class="asset-label">优惠券</text>
</view>
<view class="asset-item" @click="goToPoints">
<text class="asset-value">{{userInfo.points || 0}}</text>
<text class="asset-label">积分</text>
</view>
</view>
</view>
<!-- 我的订单 -->
<view class="order-section">
<view class="section-header" @click="goToOrderList('')">
<text class="section-title">我的订单</text>
<view class="more">
<text>全部订单</text>
<text class="iconfont icon-right"></text>
</view>
</view>
<view class="order-types">
<view class="order-type-item" @click="goToOrderList('unpaid')">
<text class="iconfont icon-wallet"></text>
<text>待付款</text>
<text class="badge" v-if="orderCount.unpaid > 0">{{orderCount.unpaid}}</text>
</view>
<view class="order-type-item" @click="goToOrderList('unshipped')">
<text class="iconfont icon-box"></text>
<text>待发货</text>
<text class="badge" v-if="orderCount.unshipped > 0">{{orderCount.unshipped}}</text>
</view>
<view class="order-type-item" @click="goToOrderList('shipped')">
<text class="iconfont icon-truck"></text>
<text>待收货</text>
<text class="badge" v-if="orderCount.shipped > 0">{{orderCount.shipped}}</text>
</view>
<view class="order-type-item" @click="goToOrderList('completed')">
<text class="iconfont icon-comment"></text>
<text>待评价</text>
<text class="badge" v-if="orderCount.completed > 0">{{orderCount.completed}}</text>
</view>
<view class="order-type-item" @click="goToAfterSale">
<text class="iconfont icon-service"></text>
<text>售后</text>
</view>
</view>
</view>
<!-- 功能列表 -->
<view class="function-section">
<view class="function-item" @click="goToAddress">
<text class="iconfont icon-location"></text>
<text>收货地址</text>
</view>
<view class="function-item" @click="goToFavorite">
<text class="iconfont icon-star"></text>
<text>我的收藏</text>
</view>
<view class="function-item" @click="goToFootprint">
<text class="iconfont icon-time"></text>
<text>浏览历史</text>
</view>
<view class="function-item" @click="goToSettings">
<text class="iconfont icon-settings"></text>
<text>设置</text>
</view>
</view>
<!-- 客服与帮助 -->
<view class="help-section">
<button class="help-btn" open-type="contact">
<text class="iconfont icon-service"></text>
<text>联系客服</text>
</button>
<view class="help-btn" @click="goToHelp">
<text class="iconfont icon-help"></text>
<text>帮助中心</text>
</view>
</view>
</view>
</template>
<script>
import { mapState, mapActions } from 'vuex';
export default {
data() {
return {
orderCount: {
unpaid: 0,
unshipped: 0,
shipped: 0,
completed: 0
}
}
},
computed: {
...mapState('user', ['userInfo', 'isLogin'])
},
onShow() {
// 检查登录状态
if (this.isLogin) {
// 获取用户信息
this.getUserInfo();
// 获取订单数量
this.getOrderCount();
}
},
methods: {
...mapActions('user', ['getUserInfo']),
...mapActions('order', ['getOrderCount']),
// 跳转到用户信息页
goToUserInfo() {
if (!this.isLogin) {
uni.navigateTo({
url: '/pages/auth/login/login'
});
return;
}
uni.navigateTo({
url: '/pages/user/info/info'
});
},
// 跳转到订单列表
goToOrderList(status) {
if (!this.isLogin) {
uni.navigateTo({
url: '/pages/auth/login/login'
});
return;
}
uni.navigateTo({
url: `/pages/order/list/list?status=${status}`
});
},
// 跳转到售后页面
goToAfterSale() {
if (!this.isLogin) {
uni.navigateTo({
url: '/pages/auth/login/login'
});
return;
}
uni.navigateTo({
url: '/pages/order/after-sale/after-sale'
});
},
// 跳转到钱包页面
goToWallet() {
if (!this.isLogin) {
uni.navigateTo({
url: '/pages/auth/login/login'
});
return;
}
uni.navigateTo({
url: '/pages/user/wallet/wallet'
});
},
// 跳转到优惠券页面
goToCoupon() {
if (!this.isLogin) {
uni.navigateTo({
url: '/pages/auth/login/login'
});
return;
}
uni.navigateTo({
url: '/pages/user/coupon/coupon'
});
},
// 跳转到积分页面
goToPoints() {
if (!this.isLogin) {
uni.navigateTo({
url: '/pages/auth/login/login'
});
return;
}
uni.navigateTo({
url: '/pages/user/points/points'
});
},
// 跳转到收货地址页面
goToAddress() {
if (!this.isLogin) {
uni.navigateTo({
url: '/pages/auth/login/login'
});
return;
}
uni.navigateTo({
url: '/pages/user/address/list'
});
},
// 跳转到收藏页面
goToFavorite() {
if (!this.isLogin) {
uni.navigateTo({
url: '/pages/auth/login/login'
});
return;
}
uni.navigateTo({
url: '/pages/user/favorite/favorite'
});
},
// 跳转到浏览历史页面
goToFootprint() {
if (!this.isLogin) {
uni.navigateTo({
url: '/pages/auth/login/login'
});
return;
}
uni.navigateTo({
url: '/pages/user/footprint/footprint'
});
},
// 跳转到设置页面
goToSettings() {
uni.navigateTo({
url: '/pages/user/settings/settings'
});
},
// 跳转到帮助中心
goToHelp() {
uni.navigateTo({
url: '/pages/help/help'
});
}
}
}
</script>
总结
通过 uni-app 开发电商应用,我们可以实现跨平台的商城功能,包括商品展示、购物车、订单管理等核心功能。本文介绍了电商应用的基本架构和关键功能实现,开发者可以在此基础上进行扩展和优化,打造功能完善的电商平台。
主要优势包括:
- 跨平台兼容:一套代码可以同时运行在多个平台,节省开发成本
- 组件化开发:利用 Vue.js 的组件化特性,提高代码复用性和可维护性
- 状态管理:使用 Vuex 进行状态管理,方便处理复杂的数据流
- 云服务集成:可以方便地集成云函数、云数据库等服务,快速实现后端功能
在实际开发中,还需要考虑性能优化、安全性、用户体验等方面,不断完善和迭代,以满足用户需求和业务发展。