You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter/Dart分离列表组件时如何移除购物车商品

在Flutter分离列表组件中移除购物车商品的解决方案

问题分析

拆分购物车列表(carts.dart)和列表项组件(cart_list_item.dart)后无法正确移除商品,核心问题有三点:

  • 列表项传递的cartIndex是固定值5,并非当前商品的真实索引
  • ApiServices中的cartList与页面维护的cartList不是同一实例,移除操作无法同步到页面
  • 移除商品后未触发页面的setState刷新列表

修复步骤与代码修改

1. 修改carts.dart:统一管理列表状态并实现移除逻辑

  • 修复FutureBuilder重复发起请求的问题
  • 添加移除商品方法,操作后调用setState刷新页面
  • 向列表项传递真实索引和移除回调
class _CartsListState extends State<CartsList> {
  List cartList = [];
  bool isLoading = true;

  getProducts() async {
    var resp = await http.get(Uri.parse("https://abc"));
    setState(() {
      cartList.addAll(jsonDecode(resp.body));
      isLoading = false;
    });
    return jsonDecode(resp.body);
  }

  // 实现移除商品方法
  void removeCartItem(int index) {
    cartList.removeAt(index);
    setState(() {}); // 刷新列表
    // 可选:调用后端接口同步移除操作
    ApiServices.removeCartItem(index);
  }

  @override
  void initState() {
    super.initState();
    getProducts();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Padding(
        padding: const EdgeInsets.all(10),
        child: isLoading
            ? const LinearProgressIndicator()
            : ListView.builder(
                itemCount: cartList.length,
                itemBuilder: (BuildContext context, int index) {
                  var path = "https://abc";
                  var img = cartList[index]['image'] ?? 'default.png';
                  return MyCartListItem(
                    cartName: cartList[index]['english_name'],
                    cartQuantity: 2,
                    cartImage: path + img,
                    cartPrice: cartList[index]['mrp'].toString(),
                    cartIndex: index, // 传递真实索引
                    onRemove: () => removeCartItem(index), // 传递移除回调
                  );
                },
              ),
      ),
    );
  }
}

2. 修改cart_list_item.dart:添加移除回调并完善数量控制

  • 在MyCartListItem中新增onRemove回调参数
  • 点击删除按钮时调用父组件的移除方法,不再直接操作ApiServices
  • 补全商品数量增减的逻辑
class MyCartListItem extends StatefulWidget {
  const MyCartListItem(
      {Key? key,
      required this.cartName,
      required this.cartQuantity,
      required this.cartImage,
      required this.cartPrice,
      required this.cartIndex,
      required this.onRemove}) // 添加移除回调
      : super(key: key);
  final String cartName;
  final int cartQuantity;
  final String cartImage;
  final String cartPrice;
  final int cartIndex;
  final VoidCallback onRemove; // 回调类型定义

  @override
  State<MyCartListItem> createState() => _MyCartListItemState();
}

class _MyCartListItemState extends State<MyCartListItem> {
  late int _itemCount;

  @override
  void initState() {
    super.initState();
    _itemCount = widget.cartQuantity; // 初始化商品数量
  }

  @override
  Widget build(BuildContext context) {
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(10.5),
        child: Row(children: [
          const SizedBox(width: 10),
          SizedBox(
            width: 70,
            height: 70,
            child: Image.network(widget.cartImage),
          ),
          const SizedBox(width: 50),
          Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Row(
                children: [
                  Text(
                    widget.cartName,
                    style: const TextStyle(overflow: TextOverflow.clip),
                  ),
                  const SizedBox(width: 10),
                ],
              ),
              const SizedBox(height: 7),
              Text(
                "Rs. ${widget.cartPrice}",
                style: const TextStyle(
                    fontWeight: FontWeight.bold, color: Colors.grey),
              ),
              const SizedBox(height: 10),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceAround,
                children: [
                  // 数量减少按钮
                  InkWell(
                    onTap: () {
                      if (_itemCount > 1) {
                        setState(() => _itemCount--);
                      }
                    },
                    child: Container(
                        height: 30,
                        width: 30,
                        decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(4),
                          color: Colors.deepOrange[50],
                        ),
                        child: const Icon(CupertinoIcons.minus)),
                  ),
                  const SizedBox(width: 10),
                  Text(_itemCount.toString()),
                  const SizedBox(width: 10),
                  // 数量增加按钮
                  InkWell(
                    onTap: () {
                      setState(() => _itemCount++);
                    },
                    child: Container(
                        height: 30,
                        width: 30,
                        decoration: BoxDecoration(
                          borderRadius: BorderRadius.circular(4),
                          color: Colors.deepOrange[50],
                        ),
                        child: const Icon(CupertinoIcons.plus)),
                  ),
                  const SizedBox(width: 15),
                  // 删除按钮
                  InkWell(
                    onTap: () {
                      widget.onRemove(); // 触发父组件的移除逻辑
                      final snackBarData = SnackBar(
                        behavior: SnackBarBehavior.floating,
                        content: Row(
                          children: const [
                            Icon(Icons.shopping_bag),
                            SizedBox(width: 10),
                            Text('商品已从购物车移除!'),
                          ],
                        ),
                      );
                      ScaffoldMessenger.of(context).showSnackBar(snackBarData);
                    },
                    child: const Icon(CupertinoIcons.trash, color: Colors.red),
                  )
                ],
              )
            ],
          )
        ]),
      ),
    );
  }
}

3. 修改api_services.dart:同步后端移除逻辑(可选)

如果需要将移除操作同步到后端,修改方法为调用对应接口:

static removeCartItem(int indexNumber) async {
  // 示例:调用后端移除接口
  // await http.post(Uri.parse("https://abc/remove-cart-item"), 
  //   body: {"item_index": indexNumber.toString()});
}

核心逻辑说明

  • 列表状态由父组件_CartsListState统一管理,保证数据源唯一且同步
  • 通过回调函数实现子组件向父组件传递操作事件,确保状态更新联动
  • 移除商品后调用setState触发页面重建,自动更新列表展示

内容的提问来源于stack exchange,提问作者swapnil mane

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 07:06:32