Flutter 3.16 状态管理:用 Bloc 模式实现购物车功能
·
以下是使用 Bloc 模式在 Flutter 3.16 中实现购物车功能的完整解决方案,包含分层架构和最佳实践:
一、架构设计
采用分层结构:
UI 层 (Widgets)
↓
Bloc 层 (业务逻辑)
↓
Repository 层 (数据源)
↓
Model 层 (数据模型)
二、模型层 (Model)
// 商品模型
class Product {
final String id;
final String name;
final double price;
Product({required this.id, required this.name, required this.price});
}
// 购物车项模型
class CartItem {
final Product product;
int quantity;
CartItem({required this.product, this.quantity = 1});
double get totalPrice => product.price * quantity;
}
// 购物车状态模型
class CartState {
final List<CartItem> items;
final double total;
const CartState({required this.items, required this.total});
// 初始状态
factory CartState.initial() =>
CartState(items: [], total: 0.0);
}
三、事件定义 (Events)
abstract class CartEvent {}
class AddProduct extends CartEvent {
final Product product;
AddProduct(this.product);
}
class RemoveProduct extends CartEvent {
final String productId;
RemoveProduct(this.productId);
}
class IncrementQuantity extends CartEvent {
final String productId;
IncrementQuantity(this.productId);
}
class DecrementQuantity extends CartEvent {
final String productId;
DecrementQuantity(this.productId);
}
class ClearCart extends CartEvent {}
四、Bloc 实现
import 'package:bloc/bloc.dart';
class CartBloc extends Bloc<CartEvent, CartState> {
CartBloc() : super(CartState.initial()) {
on<AddProduct>(_onAddProduct);
on<RemoveProduct>(_onRemoveProduct);
on<IncrementQuantity>(_onIncrementQuantity);
on<DecrementQuantity>(_onDecrementQuantity);
on<ClearCart>(_onClearCart);
}
void _onAddProduct(AddProduct event, Emitter<CartState> emit) {
final items = List<CartItem>.from(state.items);
final index = items.indexWhere((item) => item.product.id == event.product.id);
if (index >= 0) {
items[index] = CartItem(
product: items[index].product,
quantity: items[index].quantity + 1
);
} else {
items.add(CartItem(product: event.product));
}
emit(_calculateNewState(items));
}
void _onRemoveProduct(RemoveProduct event, Emitter<CartState> emit) {
final items = state.items.where((item) => item.product.id != event.productId).toList();
emit(_calculateNewState(items));
}
void _onIncrementQuantity(IncrementQuantity event, Emitter<CartState> emit) {
final items = state.items.map((item) {
if (item.product.id == event.productId) {
return CartItem(product: item.product, quantity: item.quantity + 1);
}
return item;
}).toList();
emit(_calculateNewState(items));
}
void _onDecrementQuantity(DecrementQuantity event, Emitter<CartState> emit) {
final items = state.items.map((item) {
if (item.product.id == event.productId && item.quantity > 1) {
return CartItem(product: item.product, quantity: item.quantity - 1);
}
return item;
}).toList();
emit(_calculateNewState(items));
}
void _onClearCart(ClearCart event, Emitter<CartState> emit) {
emit(CartState.initial());
}
CartState _calculateNewState(List<CartItem> items) {
final total = items.fold(0.0, (sum, item) => sum + item.totalPrice);
return CartState(items: items, total: total);
}
}
五、UI 层实现
1. 主页面
class ShoppingPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('购物车')),
body: Column(
children: [
Expanded(child: ProductGridView()),
const CartSummary(),
],
),
);
}
}
2. 商品网格
class ProductGridView extends StatelessWidget {
final products = [
Product(id: '1', name: '商品A', price: 19.99),
Product(id: '2', name: '商品B', price: 29.99),
// ...更多商品
];
@override
Widget build(BuildContext context) {
return GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 0.8,
),
itemCount: products.length,
itemBuilder: (context, index) {
return ProductCard(product: products[index]);
},
);
}
}
3. 商品卡片
class ProductCard extends StatelessWidget {
final Product product;
const ProductCard({Key? key, required this.product}) : super(key: key);
@override
Widget build(BuildContext context) {
return Card(
child: Column(
children: [
Text(product.name),
Text('¥${product.price.toStringAsFixed(2)}'),
IconButton(
icon: const Icon(Icons.add_shopping_cart),
onPressed: () => context.read<CartBloc>().add(AddProduct(product)),
)
],
),
);
}
}
4. 购物车摘要
class CartSummary extends StatelessWidget {
const CartSummary({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return BlocBuilder<CartBloc, CartState>(
builder: (context, state) {
return Container(
padding: const EdgeInsets.all(16),
color: Colors.grey[200],
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('总计: ¥${state.total.toStringAsFixed(2)}'),
ElevatedButton(
onPressed: () => context.read<CartBloc>().add(ClearCart()),
child: const Text('清空购物车'),
),
],
),
const SizedBox(height: 8),
ElevatedButton(
onPressed: () => Navigator.push(
context,
MaterialPageRoute(builder: (context) => CartDetailScreen()),
),
child: const Text('查看购物车详情'),
),
],
),
);
},
);
}
}
5. 购物车详情页
class CartDetailScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('购物车详情')),
body: BlocBuilder<CartBloc, CartState>(
builder: (context, state) {
if (state.items.isEmpty) {
return const Center(child: Text('购物车为空'));
}
return ListView.builder(
itemCount: state.items.length,
itemBuilder: (context, index) {
final item = state.items[index];
return ListTile(
title: Text(item.product.name),
subtitle: Text('单价: ¥${item.product.price.toStringAsFixed(2)}'),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
IconButton(
icon: const Icon(Icons.remove),
onPressed: () => context.read<CartBloc>().add(DecrementQuantity(item.product.id)),
),
Text('${item.quantity}'),
IconButton(
icon: const Icon(Icons.add),
onPressed: () => context.read<CartBloc>().add(IncrementQuantity(item.product.id)),
),
IconButton(
icon: const Icon(Icons.delete),
onPressed: () => context.read<CartBloc>().add(RemoveProduct(item.product.id)),
),
],
),
);
},
);
},
),
);
}
}
六、应用集成
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: BlocProvider(
create: (context) => CartBloc(),
child: const ShoppingPage(),
),
);
}
}
七、最佳实践
- 状态管理:使用
BlocBuilder精确控制 UI 重建范围 - 性能优化:
- 为列表项添加
const构造函数 - 使用
Key优化列表更新
- 为列表项添加
- 测试策略:
test('添加商品应更新状态', () { final bloc = CartBloc(); bloc.add(AddProduct(Product(id: '1', name: 'Test', price: 10.0))); expectLater( bloc.stream, emits(CartState( items: [CartItem(product: Product(id: '1', name: 'Test', price: 10.0))], total: 10.0 )) ); }); - 扩展性:
- 添加
Repository层支持网络请求 - 实现
HydratedBloc支持状态持久化
- 添加
此实现符合 Flutter 3.16 最新规范,使用 BLoC 8.x 版本,完全响应式管理购物车状态,支持商品增删改查和数量调整,并确保 UI 与业务逻辑完全分离。
更多推荐
所有评论(0)