Taro多端电商项目(仿京东)完整开发指南
本指南面向前端开发者,全面覆盖Taro多端电商项目(仿京东)从规划到落地的全流程。通过"需求分析-框架设计-模块实现-测试部署"的逻辑脉络,结合京东电商核心业务场景,提供可复用的代码示例与标准化的开发流程,助力开发者快速搭建支持微信小程序、H5、App多端运行的电商系统。

一、需求分析
需求分析是项目开发的基础,需明确目标用户、核心业务场景及功能优先级,为后续开发提供方向指引。
1.1 用户画像
-
核心用户:普通消费者 - 年龄18-45岁,习惯线上购物,关注商品性价比、物流速度,常用微信小程序、H5或App访问电商平台,需求是快速找到商品、便捷下单、实时跟踪订单。
-
次要用户:商家 - 需入驻平台发布商品、管理订单、处理售后,需求是简单易用的商家管理功能。
-
平台运营者 - 负责平台活动策划、商品审核、数据监控,需求是完善的运营管理后台与数据统计功能。
1.2 核心业务场景
-
商品浏览与筛选:用户通过分类导航、搜索框查找商品,可按价格、销量、评分等条件筛选排序,查看商品详情(图文介绍、规格、评价)。
-
购物车管理:用户添加商品到购物车,支持修改商品数量、选择规格、删除商品,结算时自动计算金额。
-
下单与支付:用户确认订单信息(收货地址、商品清单、金额),选择支付方式(微信支付、支付宝)完成付款,生成订单记录。
-
订单管理:用户查看订单列表(待付款、待发货、待收货、已完成),跟踪物流信息,申请售后(退款、退货)。
-
用户中心:用户登录/注册、管理个人信息(头像、昵称)、收货地址、查看收藏商品、浏览历史。
-
营销活动:平台开展秒杀、优惠券、满减等活动,用户参与活动享受优惠。
1.3 功能优先级
| 优先级 | 功能模块 | 说明 |
|---|---|---|
| P0(核心必做) | 商品展示、搜索筛选、购物车、下单支付、订单列表、用户登录注册、收货地址管理 | 保障电商核心交易流程顺畅 |
| P1(重要功能) | 商品评价、物流跟踪、售后申请、收藏商品、浏览历史 | 提升用户购物体验,完善交易闭环 |
| P2(次要功能) | 营销活动(秒杀、优惠券)、商家管理、数据统计、消息推送 | 提升平台竞争力与运营能力,可后续迭代 |
二、功能说明
本节详细罗列核心模块功能,并明确多端适配要求,确保功能在不同平台均能正常运行且体验一致。
2.1 核心模块功能
2.1.1 商品展示模块
-
首页商品推荐:展示热门商品、新品、活动商品,支持轮播图展示活动海报。
-
商品分类:按一级分类、二级分类展示商品,支持分类导航切换。
-
商品详情:展示商品图文介绍、规格参数、价格、库存、销量,提供加入购物车、立即购买按钮。
-
商品评价:展示用户评价列表,支持按好评、中评、差评筛选,显示评价图片。
2.1.2 搜索筛选模块
-
关键词搜索:支持输入商品名称、关键词搜索,显示搜索历史、热门搜索推荐。
-
高级筛选:支持按价格区间、销量高低、评分高低、品牌、规格等条件筛选。
-
搜索结果排序:支持默认、价格、销量、评分排序,显示筛选结果数量。
2.1.3 购物车模块
-
商品管理:添加商品到购物车,支持修改商品数量(增减、直接输入)、选择商品规格。
-
批量操作:支持全选/取消全选、批量删除商品。
-
价格计算:自动计算选中商品的总金额、优惠金额,显示实付金额。
-
库存校验:结算前校验商品库存,提示缺货商品。
2.1.4 订单管理模块
-
订单创建:确认收货地址、商品清单、金额后生成订单,支持选择发票类型。
-
订单列表:按订单状态(待付款、待发货、待收货、已完成、已取消)分类展示,显示订单编号、时间、金额、商品缩略图。
-
订单详情:展示订单完整信息(商品清单、收货信息、支付信息、物流信息)。
-
订单操作:待付款订单支持付款、取消;待收货订单支持确认收货;已完成订单支持申请售后、查看评价。
2.1.5 支付集成模块
-
支付方式选择:支持微信支付(小程序/H5/App)、支付宝支付(H5/App)。
-
支付流程:唤起支付接口,处理支付成功、失败、取消回调,更新订单状态。
-
支付记录:查看支付历史,显示支付时间、金额、支付方式、订单编号。
2.1.6 用户中心模块
-
登录/注册:支持手机号验证码登录、微信快捷登录(小程序/App)、账号密码登录。
-
个人信息管理:修改头像、昵称、性别、生日等个人信息。
-
收货地址管理:添加、编辑、删除收货地址,设置默认地址,支持地址智能联想。
-
收藏与历史:查看收藏商品列表、浏览历史记录,支持取消收藏、清空历史。
2.2 多端适配要求
| 适配平台 | 适配要求 | 特殊处理 |
|---|---|---|
| 微信小程序 | 1. 遵循小程序界面规范,适配不同屏幕尺寸;2. 保证页面加载速度,避免过大图片;3. 兼容小程序基础库最新3个版本 | 1. 支付集成微信支付SDK;2. 登录使用微信小程序登录接口;3. 采用小程序分包加载优化体积 |
| H5 | 1. 响应式布局,适配PC、平板、手机等不同设备;2. 兼容主流浏览器(Chrome、Firefox、Safari、Edge);3. 优化移动端触摸体验 | 1. 支付集成微信H5支付、支付宝H5支付;2. 处理浏览器兼容性问题(如CSS3属性、JS API);3. 支持地址栏分享功能 |
| App(React Native) | 1. 适配iOS、Android不同系统版本及机型;2. 保证页面流畅度,减少卡顿;3. 遵循原生App交互规范 | 1. 集成原生支付SDK;2. 使用原生组件优化体验(如导航栏、tabbar);3. 处理离线缓存、网络状态监听 |
三、项目框架设计
基于Taro框架特性,结合电商项目需求,进行技术栈选型、目录结构设计、状态管理等核心框架设计,确保项目架构清晰、可扩展。
3.1 技术栈选型依据
选型核心原则:多端适配兼容性好、开发效率高、生态完善、性能优异,具体选型如下:
-
核心框架:Taro 3.x - 支持一套代码编译为多端应用,兼容性强,API设计贴近React,前端开发者易上手。
-
开发语言:TypeScript - 提供类型校验,减少运行时错误,提升代码可维护性,适配大型电商项目开发。
-
UI组件库:Taro UI Vue3 / NutUI - 提供丰富的电商类组件(商品卡片、购物车、订单列表等),支持多端适配,可直接复用。
-
状态管理:Redux Toolkit - 简化Redux使用流程,内置中间件,适合管理电商项目复杂状态(购物车、用户信息、订单状态等)。
-
路由管理:Taro 内置路由 - 统一的路由配置方式,支持多端路由跳转、参数传递,适配不同平台路由特性。
-
API请求:Axios + Taro 请求适配 - Axios功能强大,支持拦截器、请求取消等,结合Taro适配多端请求特性。
-
样式解决方案:SCSS + CSS Modules - SCSS支持嵌套、变量、混合等特性,CSS Modules避免样式冲突,提升样式可维护性。
-
构建工具:Taro CLI - 内置构建打包能力,支持多端差异化构建,可配置自定义构建规则。
3.2 目录结构设计
采用模块化、分层的目录结构,便于团队协作与后期维护:
plaintext
src/
├── api/ # API请求封装
│ ├── index.ts # 请求拦截器、响应拦截器配置
│ ├── goods.ts # 商品相关接口
│ ├── cart.ts # 购物车相关接口
│ ├── order.ts # 订单相关接口
│ └── user.ts # 用户相关接口
├── assets/ # 静态资源
│ ├── images/ # 图片资源(分模块存放)
│ ├── styles/ # 全局样式、SCSS变量、混合
│ └── fonts/ # 字体资源
├── components/ # 公共组件
│ ├── common/ # 基础组件(按钮、输入框、加载中)
│ ├── goods/ # 商品相关组件(商品卡片、商品详情页组件)
│ ├── cart/ # 购物车相关组件(购物车项、数量选择器)
│ ├── order/ # 订单相关组件(订单项、订单状态标签)
│ └── user/ # 用户相关组件(地址项、登录表单)
├── pages/ # 页面组件(按模块划分)
│ ├── index/ # 首页
│ ├── goods/ # 商品相关页面(列表、详情、评价)
│ ├── search/ # 搜索页面
│ ├── cart/ # 购物车页面
│ ├── order/ # 订单相关页面(列表、详情、确认订单)
│ ├── pay/ # 支付页面
│ └── user/ # 用户中心相关页面
├── store/ # 状态管理(Redux Toolkit)
│ ├── index.ts # store配置
│ ├── slices/ # 状态切片(userSlice、cartSlice、goodsSlice)
│ └── hooks.ts # 自定义hooks(useAppDispatch、useAppSelector)
├── router/ # 路由配置
│ ├── index.ts # 路由表配置
│ └── hooks.ts # 路由相关hooks(导航守卫、跳转方法封装)
├── utils/ # 工具函数
│ ├── index.ts # 通用工具(格式转换、正则校验)
│ ├── storage.ts # 本地存储工具(适配多端)
│ ├── price.ts # 价格计算工具
│ └── device.ts # 设备信息工具(判断平台)
├── config/ # 项目配置
│ ├── index.ts # 全局配置(接口基础地址、环境变量)
│ └── adapt.ts # 多端适配配置
├── types/ # TypeScript类型定义
│ ├── goods.ts # 商品相关类型
│ ├── cart.ts # 购物车相关类型
│ ├── order.ts # 订单相关类型
│ └── user.ts # 用户相关类型
├── app.tsx # 入口组件
├── app.config.ts # 全局配置(页面路由、窗口样式)
└── app.scss # 全局样式
3.3 状态管理方案
采用Redux Toolkit进行状态管理,按模块拆分状态切片,实现状态的集中管理与复用:
3.3.1 核心状态切片设计
-
userSlice:管理用户状态(登录状态、用户信息、收货地址列表、默认地址)。
-
cartSlice:管理购物车状态(购物车列表、选中商品数量、总金额、是否全选)。
-
goodsSlice:管理商品相关状态(商品列表、商品详情、搜索条件、筛选结果)。
-
orderSlice:管理订单相关状态(订单列表、当前订单信息、支付状态)。
3.3.2 Store配置实现
typescript
// src/store/index.ts
import { configureStore } from '@reduxjs/toolkit';
import userSlice from './slices/userSlice';
import cartSlice from './slices/cartSlice';
import goodsSlice from './slices/goodsSlice';
import orderSlice from './slices/orderSlice';
// 配置store
export const store = configureStore({
reducer: {
user: userSlice,
cart: cartSlice,
goods: goodsSlice,
order: orderSlice,
},
// 关闭序列化检查(适配多端存储复杂数据)
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: false,
}),
});
// 定义RootState和AppDispatch类型,方便组件使用
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;
3.3.3 自定义Hooks封装
typescript
// src/store/hooks.ts
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
import type { RootState, AppDispatch } from './index';
// 自定义useDispatch和useSelector,自带类型提示
export const useAppDispatch = () => useDispatch<AppDispatch>();
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
3.4 路由配置
基于Taro内置路由,配置统一的路由表,封装跳转方法,支持多端路由适配:
3.4.1 路由表配置
typescript
// src/router/index.ts
import { RouteConfig } from '@tarojs/taro';
// 路由表
const routes: RouteConfig[] = [
{
path: '/pages/index/index',
name: '首页',
meta: {
showTabBar: true, // 是否显示底部tab
requireAuth: false, // 是否需要登录
},
},
{
path: '/pages/goods/list',
name: '商品列表',
meta: {
showTabBar: false,
requireAuth: false,
},
},
{
path: '/pages/goods/detail/:id',
name: '商品详情',
meta: {
showTabBar: false,
requireAuth: false,
},
},
{
path: '/pages/cart/index',
name: '购物车',
meta: {
showTabBar: true,
requireAuth: true,
},
},
{
path: '/pages/order/list',
name: '订单列表',
meta: {
showTabBar: false,
requireAuth: true,
},
},
{
path: '/pages/user/index',
name: '用户中心',
meta: {
showTabBar: true,
requireAuth: true,
},
},
// 更多路由...
];
export default routes;
3.4.2 路由跳转封装
typescript
// src/router/hooks.ts
import Taro from '@tarojs/taro';
import routes from './index';
import { useAppSelector } from '../store/hooks';
// 跳转方法封装
export const useNavigate = () => {
// 获取登录状态
const { isLogin } = useAppSelector((state) => state.user);
// 导航跳转
const navigateTo = (path: string, params?: Record<string, any>) => {
// 检查是否需要登录
const route = routes.find((item) => item.path === path);
if (route?.meta.requireAuth && !isLogin) {
// 未登录,跳转登录页
Taro.navigateTo({ url: '/pages/user/login' });
return;
}
// 拼接参数
let url = path;
if (params) {
const queryStr = Object.entries(params)
.map(([key, value]) => `${key}=${value}`)
.join('&');
url += `?${queryStr}`;
}
// 执行跳转
Taro.navigateTo({ url });
};
// 重定向跳转
const redirectTo = (path: string, params?: Record<string, any>) => {
let url = path;
if (params) {
const queryStr = Object.entries(params)
.map(([key, value]) => `${key}=${value}`)
.join('&');
url += `?${queryStr}`;
}
Taro.redirectTo({ url });
};
return { navigateTo, redirectTo };
};
3.5 API请求封装
基于Axios封装API请求,实现请求拦截、响应拦截、错误处理、多端适配:
3.5.1 请求配置
typescript
// src/api/index.ts
import axios from 'axios';
import Taro from '@tarojs/taro';
import { baseUrl } from '../config';
// 创建axios实例
const service = axios.create({
baseURL: baseUrl, // 接口基础地址
timeout: 10000, // 请求超时时间
});
// 请求拦截器
service.interceptors.request.use(
(config) => {
// 添加请求头(如token)
const token = Taro.getStorageSync('token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
// 显示加载中
Taro.showLoading({ title: '加载中...', mask: true });
return config;
},
(error) => {
// 隐藏加载中
Taro.hideLoading();
// 处理请求错误
console.error('请求错误:', error);
Taro.showToast({ title: '请求失败', icon: 'none' });
return Promise.reject(error);
}
);
// 响应拦截器
service.interceptors.response.use(
(response) => {
// 隐藏加载中
Taro.hideLoading();
const res = response.data;
// 业务错误处理(如token过期、权限不足)
if (res.code !== 200) {
Taro.showToast({ title: res.msg || '请求失败', icon: 'none' });
// token过期,跳转登录页
if (res.code === 401) {
Taro.removeStorageSync('token');
Taro.navigateTo({ url: '/pages/user/login' });
}
return Promise.reject(res);
}
return res.data;
},
(error) => {
// 隐藏加载中
Taro.hideLoading();
// 处理网络错误
console.error('响应错误:', error);
Taro.showToast({ title: '网络异常,请稍后重试', icon: 'none' });
return Promise.reject(error);
}
);
export default service;
3.5.2 接口封装示例
typescript
// src/api/goods.ts
import service from './index';
import { GoodsListParams, GoodsListRes, GoodsDetailRes } from '../types/goods';
// 获取商品列表
export const getGoodsList = (params: GoodsListParams) => {
return service<GoodsListRes>({
url: '/goods/list',
method: 'GET',
params,
});
};
// 获取商品详情
export const getGoodsDetail = (id: string | number) => {
return service<GoodsDetailRes>({
url: `/goods/detail/${id}`,
method: 'GET',
});
};
// 添加商品收藏
export const collectGoods = (id: string | number) => {
return service({
url: '/goods/collect',
method: 'POST',
data: { goodsId: id },
});
};
3.6 多端适配架构
基于Taro的多端编译能力,采用"统一代码+差异化适配"的架构,实现一套代码多端运行:
3.6.1 差异化适配方案
-
组件适配:使用Taro内置组件或多端兼容的UI组件库,若需原生组件,采用条件编译区分平台。
-
API适配 :使用Taro封装的统一API,若平台特有API,通过
process.env.TARO_ENV判断平台后调用。 -
样式适配:使用CSS变量、媒体查询、Flex/Grid布局实现响应式,小程序端使用rpx单位,H5/App使用rem/vw单位。
-
配置适配 :在
app.config.ts或页面配置文件中,通过h5、mini、rn字段配置不同平台的专属配置。
3.6.2 条件编译示例
typescript
// 组件适配示例
import Taro from '@tarojs/taro';
const MyComponent = () => {
return (
<view>
{/* 统一组件 */}
<Button type="primary" onClick={handleClick}>
统一按钮
</Button>
{/* 平台差异化组件 */}
{process.env.TARO_ENV === 'weapp' ? (
<weapp-native-component /> // 微信小程序原生组件
) : process.env.TARO_ENV === 'h5' ? (
<h5-native-component /> // H5原生组件
) : null}
</view>
);
};
// API适配示例
const getLocation = () => {
if (process.env.TARO_ENV === 'weapp') {
// 微信小程序获取位置
Taro.getLocation({ type: 'gcj02' });
} else if (process.env.TARO_ENV === 'h5') {
// H5获取位置(使用浏览器API)
navigator.geolocation.getCurrentPosition((position) => {
console.log(position);
});
}
};
3.6.3 多端配置示例
typescript
// src/app.config.ts
export default {
pages: [
'pages/index/index',
'pages/goods/list',
// 其他页面...
],
window: {
backgroundTextStyle: 'light',
navigationBarBackgroundColor: '#fff',
navigationBarTitleText: '仿京东电商',
navigationBarTextStyle: 'black',
},
// 微信小程序专属配置
mini: {
programName: '仿京东电商',
appid: 'wx1234567890abcdef',
subpackages: [
{
root: 'pages/goods/',
pages: ['detail', 'list'],
},
], // 分包加载
},
// H5专属配置
h5: {
router: {
mode: 'hash', // 路由模式
},
devServer: {
port: 3000, // 开发服务器端口
},
},
// App专属配置
rn: {
navigationBar: {
hidden: false, // 是否隐藏导航栏
},
},
};
四、模块分析
本节对核心业务模块进行详细分析,包括业务逻辑、数据流转与组件拆分思路,为开发实现提供清晰指引。
4.1 商品展示模块
4.1.1 业务逻辑
- 首页加载时,调用热门商品、新品、活动商品接口,展示商品列表与轮播图;2. 用户点击分类导航,加载对应分类的商品列表;3. 用户点击商品卡片,跳转商品详情页,加载商品详情、规格、评价数据;4. 用户查看商品评价,支持筛选不同类型评价。
4.1.2 数据流转
-
页面初始化 → 调用商品列表/详情接口 → 接口返回数据 → 存储到goodsSlice状态 → 组件从状态中获取数据渲染。
-
用户筛选评价 → 调用评价列表接口(携带筛选参数) → 返回筛选后数据 → 更新页面渲染。
-
用户收藏商品 → 调用收藏接口 → 接口返回成功 → 更新商品收藏状态 → 提示收藏成功。
4.1.3 组件拆分
-
基础组件:
-
GoodsCard:商品卡片组件,接收商品信息(图片、名称、价格、销量),展示商品卡片,支持点击跳转详情。
-
SwiperBanner:轮播图组件,接收图片列表,支持自动轮播、点击跳转。
-
CategoryNav:分类导航组件,接收分类列表,支持点击切换分类。
-
-
页面组件:
-
IndexPage:首页,集成SwiperBanner、CategoryNav、GoodsCard,展示各类商品。
-
GoodsListPage:商品列表页,接收分类ID参数,展示对应分类商品,支持分页加载。
-
GoodsDetailPage:商品详情页,展示商品图文、规格选择器、加入购物车/立即购买按钮,集成评价列表组件。
-
GoodsCommentPage:商品评价页,展示评价列表,支持筛选评价类型。
-
4.2 购物车模块
4.2.1 业务逻辑
- 用户进入购物车,加载购物车列表数据,展示商品信息、数量、价格;2. 用户可修改商品数量,系统自动计算总金额;3. 支持全选/取消全选,选中商品金额实时更新;4. 用户点击结算,校验商品库存,若缺货提示用户,否则跳转确认订单页。
4.2.2 数据流转
-
进入购物车页面 → 调用购物车列表接口 → 数据存储到cartSlice → 组件渲染购物车列表。
-
修改商品数量 → 调用更新购物车接口 → 接口返回成功 → 更新cartSlice状态 → 重新计算总金额。
-
点击全选 → 切换cartSlice中全选状态 → 更新所有商品的选中状态 → 重新计算总金额。
-
点击结算 → 校验选中商品库存 → 库存充足 → 跳转确认订单页并携带选中商品数据;库存不足 → 提示缺货商品。
4.2.3 组件拆分
-
基础组件:
-
CartItem:购物车项组件,展示商品信息、选中状态、数量选择器、删除按钮。
-
QuantitySelector:数量选择器组件,支持增减数量、直接输入,限制最小为1。
-
CartFooter:购物车底部组件,展示全选按钮、选中数量、总金额、结算按钮。
-
-
页面组件:
- CartPage:购物车主页面,集成CartItem、CartFooter,处理购物车相关操作逻辑。
4.3 订单管理模块
4.3.1 业务逻辑
- 用户在确认订单页选择收货地址、商品清单,提交订单生成订单记录;2. 跳转到支付页面,选择支付方式完成支付;3. 支付成功后,更新订单状态为"待发货",返回订单列表;4. 用户可按状态查看订单列表,点击订单查看详情,进行对应操作(确认收货、申请售后)。
4.3.2 数据流转
-
确认订单页 → 获取购物车选中商品数据、用户收货地址 → 提交订单接口 → 生成订单ID → 跳转支付页面。
-
支付页面 → 调用支付接口 → 支付成功 → 调用更新订单状态接口 → 跳转订单详情页(显示支付成功)。
-
订单列表页 → 调用订单列表接口(携带状态参数) → 数据存储到orderSlice → 组件渲染订单列表。
-
确认收货 → 调用确认收货接口 → 接口返回成功 → 更新订单状态 → 重新加载订单列表。
4.3.3 组件拆分
-
基础组件:
-
OrderItem:订单项组件,展示订单编号、时间、商品缩略图、金额、订单状态。
-
OrderStatusTag:订单状态标签组件,根据订单状态显示不同颜色和文字(待付款、待发货等)。
-
OrderGoodsList:订单商品列表组件,展示订单中的商品清单(图片、名称、规格、数量、单价)。
-
AddressItem:地址项组件,展示收货地址信息,支持选择地址。
-
-
页面组件:
-
ConfirmOrderPage:确认订单页,集成AddressItem、OrderGoodsList,展示订单金额,提交订单。
-
PayPage:支付页面,展示支付金额,支持选择支付方式,唤起支付接口。
-
OrderListPage:订单列表页,集成OrderItem,支持按状态筛选订单。
-
OrderDetailPage:订单详情页,集成OrderGoodsList、OrderStatusTag,展示订单完整信息,提供订单操作按钮。
-
4.4 用户中心模块
4.4.1 业务逻辑
- 用户未登录时,用户中心显示登录/注册按钮;2. 登录后展示用户头像、昵称,提供个人信息修改入口;3. 支持查看收货地址列表,进行添加、编辑、删除、设置默认地址操作;4. 展示收藏商品列表、浏览历史,支持取消收藏、清空历史。
4.4.2 数据流转
-
用户登录 → 调用登录接口 → 返回token和用户信息 → 存储token到本地缓存,用户信息存储到userSlice → 刷新页面展示登录后状态。
-
修改个人信息 → 调用更新用户信息接口 → 接口返回成功 → 更新userSlice中用户信息 → 页面重新渲染。
-
加载收货地址 → 调用地址列表接口 → 数据存储到userSlice → 组件渲染地址列表。
-
添加/编辑地址 → 调用添加/更新地址接口 → 接口返回成功 → 重新加载地址列表。
4.4.3 组件拆分
-
基础组件:
-
UserAvatar:用户头像组件,展示头像,支持点击上传头像。
-
AddressForm:地址表单组件,用于添加/编辑收货地址,包含姓名、手机号、地址、邮编等字段。
-
CollectItem:收藏商品项组件,展示收藏商品信息,支持取消收藏。
-
-
页面组件:
-
UserIndexPage:用户中心首页,展示用户信息、功能入口(地址管理、收藏、历史、订单)。
-
LoginPage:登录页面,支持手机号验证码登录、微信快捷登录。
-
UserInfoPage:个人信息修改页面,集成UserAvatar,展示并修改用户信息。
-
AddressListPage:地址列表页,集成AddressItem,展示地址列表,提供添加地址入口。
-
AddressEditPage:地址编辑页,集成AddressForm,用于添加/编辑地址。
-
CollectPage:收藏商品页,集成CollectItem,展示收藏商品列表。
-
五、全流程实操指南
本节从环境安装到核心模块代码实现,提供 step-by-step 实操指南,包含关键代码片段与注释,确保开发者可直接复用。
5.1 环境安装与项目初始化
5.1.1 安装Taro CLI
bash
# 全局安装Taro CLI(使用npm)
npm install -g @tarojs/cli
# 验证安装成功
taro -v
# 输出示例:Taro v3.6.12
5.1.2 创建Taro项目
bash
# 创建项目(项目名称:taro-jd-ecommerce,模板:react-ts)
taro init taro-jd-ecommerce
# 项目创建过程中按如下选择:
# 1. 选择框架:React
# 2. 选择语言:TypeScript
# 3. 选择CSS预处理器:SCSS
# 4. 选择模板源:默认模板
# 5. 选择UI组件库:Taro UI Vue3(或NutUI)
# 6. 是否需要状态管理:Redux
# 7. 是否需要TypeScript类型检查:是
# 8. 是否初始化git仓库:是
5.1.3 项目配置调整
修改src/app.config.ts,配置页面路由、窗口样式、多端配置(参考3.6.3节多端配置示例)。
5.1.4 安装依赖包
bash
# 进入项目目录
cd taro-jd-ecommerce
# 安装axios(API请求)、redux-toolkit(状态管理)
npm install axios @reduxjs/toolkit react-redux
5.2 核心基础模块实现
5.2.1 全局配置实现
typescript
// src/config/index.ts
// 环境变量区分(开发/生产)
const isProd = process.env.NODE_ENV === 'production';
export default {
// 接口基础地址
baseUrl: isProd ? 'https://api.jd-demo.com' : 'http://localhost:3000/api',
// 超时时间
timeout: 10000,
// 存储键名
storageKey: {
token: 'jd_ecommerce_token',
userInfo: 'jd_ecommerce_userInfo',
},
};
5.2.2 工具函数实现(本地存储)
typescript
// src/utils/storage.ts
import Taro from '@tarojs/taro';
import { storageKey } from '../config';
// 存储工具类
class Storage {
// 存储token
setToken(token: string) {
Taro.setStorageSync(storageKey.token, token);
}
// 获取token
getToken() {
return Taro.getStorageSync(storageKey.token) || '';
}
// 移除token
removeToken() {
Taro.removeStorageSync(storageKey.token);
}
// 存储用户信息
setUserInfo(userInfo: any) {
Taro.setStorageSync(storageKey.userInfo, userInfo);
}
// 获取用户信息
getUserInfo() {
return Taro.getStorageSync(storageKey.userInfo) || null;
}
// 清空存储
clear() {
Taro.clearStorageSync();
}
}
export default new Storage();
5.2.3 API请求封装实现
参考3.5.1节和3.5.2节代码,实现API请求拦截、响应拦截及接口封装。
5.2.4 状态管理实现(以cartSlice为例)
Plain
// src/store/slices/cartSlice.ts
import { createSlice, createAsyncThunk } from '@reduxjs/toolkit';
import { getCartList, updateCartNum, deleteCartItem } from '../../api/cart';
import { CartItemType } from '../../types/cart';
// 定义初始状态
interface CartState {
cartList: CartItemType[]; // 购物车列表
totalNum: number; // 选中商品总数
totalPrice: number; // 选中商品总金额
isAllChecked: boolean; // 是否全选
loading: boolean; // 加载状态
}
const initialState: CartState = {
cartList: [],
totalNum: 0,
totalPrice: 0,
isAllChecked: false,
loading: false,
};
// 异步获取购物车列表
export const fetchCartList = createAsyncThunk(
'cart/fetchCartList',
async (_, { rejectWithValue }) => {
try {
const data = await getCartList();
return data;
} catch (error) {
return rejectWithValue(error);
}
}
);
// 异步更新购物车商品数量
export const updateCartQuantity = createAsyncThunk(
'cart/updateCartQuantity',
async ({ id, num }: { id: number; num: number }, { rejectWithValue }) => {
try {
const data = await updateCartNum(id, num);
return { id, num };
} catch (error) {
return rejectWithValue(error);
}
}
);
// 异步删除购物车商品
export const removeCartItem = createAsyncThunk(
'cart/removeCartItem',
async (id: number, { rejectWithValue }) => {
try {
await deleteCartItem(id);
return id;
} catch (error) {
return rejectWithValue(error);
}
}
);
// 计算选中商品总数和总金额
const calculateSelected = (cartList: CartItemType[]) => {
let totalNum = 0;
let totalPrice = 0;
cartList.forEach(item => {
if (item.checked) {
totalNum += item.num;
totalPrice += item.price * item.num;
}
});
return { totalNum, totalPrice };
};
// 创建购物车切片
const cartSlice = createSlice({
name: 'cart',
initialState,
reducers: {
// 切换商品选中状态
toggleItemChecked: (state, action) => {
const id = action.payload;
const item = state.cartList.find(item => item.id === id);
if (item) {
item.checked = !item.checked;
}
// 重新计算总数和总金额
const { totalNum, totalPrice } = calculateSelected(state.cartList);
state.totalNum = totalNum;
state.totalPrice = totalPrice;
// 判断是否全选
state.isAllChecked = state.cartList.every(item => item.checked);
},
// 全选/取消全选
toggleAllChecked: (state) => {
state.isAllChecked = !state.isAllChecked;
state.cartList.forEach(item => {
item.checked = state.isAllChecked;
});
// 重新计算总数和总金额
const { totalNum, totalPrice } = calculateSelected(state.cartList);
state.totalNum = totalNum;
state.totalPrice = totalPrice;
},
// 清空购物车
clearCart: (state) => {
state.cartList = [];
state.totalNum = 0;
state.totalPrice = 0;
state.isAllChecked = false;
},
},
extraReducers: (builder) => {
builder
// 获取购物车列表
.addCase(fetchCartList.pending, (state) => {
state.loading = true;
})
.addCase(fetchCartList.fulfilled, (state, action) => {
state.loading = false;
state.cartList = action.payload.map((item: CartItemType) => ({ ...item, checked: false }));
// 初始化计算总数和总金额(默认未选中)
const { totalNum, totalPrice } = calculateSelected(state.cartList);
state.totalNum = totalNum;
state.totalPrice = totalPrice;
state.isAllChecked = false;
})
.addCase(fetchCartList.rejected, (state) => {
state.loading = false;
})
// 更新商品数量
.addCase(updateCartQuantity.fulfilled, (state, action) => {
const { id, num } = action.payload;
const item = state.cartList.find(item => item.id === id);
if (item) {
item.num = num;
}
// 重新计算总数和总金额
const { totalNum, totalPrice } = calculateSelected(state.cartList);
state.totalNum = totalNum;
state.totalPrice = totalPrice;
})
// 删除商品
.addCase(removeCartItem.fulfilled, (state, action) => {
const id = action.payload;
state.cartList = state.cartList.filter(item => item.id !== id);
// 重新计算总数和总金额
const { totalNum, totalPrice } = calculateSelected(state.cartList);
state.totalNum = totalNum;
state.totalPrice = totalPrice;
// 判断是否全选
state.isAllChecked = state.cartList.every(item => item.checked);
});
},
});
// 导出actions
export const { toggleItemChecked, toggleAllChecked, clearCart } = cartSlice.actions;
// 导出reducer
export default cartSlice.reducer;