UniappDay05

发布于:2025-08-01 ⋅ 阅读:(15) ⋅ 点赞:(0)

1.地址模块-准备工作

  1. 新建分包页面
  2. 静态结构
  3. 动态设置标题
// 获取页面参数
const query = defineProps<{
  // id ke有可无
  id?: string
}>()

// 动态设置标题
uni.setNavigationBarTitle({ title: query.id ? '修改地址' : '新建地址' })

2.新建地址

  1. 封装API接口
  2. 定义参数类型
import { http } from '@/utils/http'
import { AddressParams } from '@/types/address'

export const postMemberAddressAPI = (data: AddressParams) => {
  return http({
    method: 'POST',
    url: '/member/address',
    data,
  })
}
  1. 收集表单数据
  2. 点击保存调用
  3. 成功提示
  4. 返回上一页
// 收集地、区信息
const onRegionChange: UniHelper.RegionPickerOnChange = (ev) => {
  // 前端展示用
  form.value.fullLocation = ev.detail.value.join(' ')
  // 后端展示
  const [provinceCode, cityCode, countyCode] = ev.detail.code!
  // 合并方法
  Object.assign(form.value, { provinceCode, cityCode, countyCode })
}

//收集是否默认收货地址
const onSwitchChange: UniHelper.SwitchOnChange = (ev) => {
  form.value.isDefault = ev.detail.value ? 1 : 0
}

// 体检表单
const onSubmit = async () => {
  // 新建地址请求
  const res = await postMemberAddressAPI(form.value)
  // 成功提示
  uni.showToast({ icon: 'none', title: '添加成功' })
  // 返回上一页
  setTimeout(() => {
    uni.navigateBack()
  }, 500)
}


<template>
  <view class="content">
    <form>
      <!-- 表单内容 -->
      <view class="form-item">
        <text class="label">收货人</text>
        <input class="input" placeholder="请填写收货人姓名" v-model="form.receiver" />
      </view>
      <view class="form-item">
        <text class="label">手机号码</text>
        <input class="input" placeholder="请填写收货人手机号码" v-model="form.contact" />
      </view>
      <view class="form-item">
        <text class="label">所在地区</text>
        <picker
          class="picker"
          @change="onRegionChange"
          mode="region"
          :value="form.fullLocation.split(' ')"
        >
          <view v-if="form.fullLocation">{{ form.fullLocation }}</view>
          <view v-else class="placeholder">请选择省/市/区(县)</view>
        </picker>
      </view>
      <view class="form-item">
        <text class="label">详细地址</text>
        <input class="input" placeholder="街道、楼牌号等信息" v-model="form.address" />
      </view>
      <view class="form-item">
        <label class="label">设为默认地址</label>
        <switch
          class="switch"
          @change="onSwitchChange"
          color="#27ba9b"
          :checked="form.isDefault === 1"
        />
      </view>
    </form>
  </view>
  <!-- 提交按钮 -->
  <button class="button" @tap="onSubmit">保存并使用</button>
</template>

3.列表渲染

  1. 封装API接口
// 获取收货地址列表
export const getMemberAddressAPI = () => {
  return http<AddressItem[]>({
    method: 'GET',
    url: '/member/address',
  })
}
  1. 初始化调用
// 获取收货地址列表数据
const addressList = ref<AddressItem[]>([])
const getMemberAddressData = async () => {
  const res = await getMemberAddressAPI()
  addressList.value = res.result
}

// 初始化
onShow(() => {
  getMemberAddressData()
})
  1. 定义类型(复用)
  2. 渲染列表
  <!-- 收货地址项 -->
          <view class="item" v-for="item in addressList" :key="item.id">
            <view class="item-content">
              <view class="user">
                {{ item.receiver }}
                <text class="contact">{{ item.contact }}</text>
                <text v-if="item.isDefault" class="badge">默认</text>
              </view>
              <view class="locate">{{ item.fullLocation }} {{ item.address }}</view>
              <navigator
                class="edit"
                hover-class="none"
                :url="`/pagesMember/address-form/address-form?id=${item.id}`"
              >
                修改
              </navigator>
            </view>
          </view>

注意事项:列表地址通过onShow初始化调用,因为新建地址成功后,需要显示最新收货地址列表

4.修改地址-数据回显

  1. 封装API接口
// 获取收货地址详情
// 获取一个收货地址,就不用写数组格式
export const getMemberAddressByIdAPI = (id: string) => {
  return http<AddressItem>({
    method: 'GET',
    url: `/member/address/${id}`,
  })
}
  1. 若有地址id,则初始化调用
  2. 表单数据回显
// 获取页面参数
const query = defineProps<{
  // id ke有可无
  id?: string
}>()

// 获取收货地址详情数据
const getMemberAddressByIdData = async () => {
  //确保query.id不是undefine
  if (query.id) {
    // 发送请求
    const res = await getMemberAddressByIdAPI(query.id)
    //实现数据回显,将数据合并
    Object.assign(form.value, res.result)
  }
}

// 页面加载
onLoad(() => {
  getMemberAddressByIdData()
})

5.修改地址-保存修改

在这里插入图片描述
新建API

// 修改收货地址
export const putMemberAddressByIdAPI = (id: string, data: AddressParams) => {
  return http({
    method: 'PUT',
    url: `/member/address/${id}`,
    data,
  })
}

修改地址

// 提交表单
const onSubmit = async () => {
  if (query.id) {
    // 修改地址
    await putMemberAddressByIdAPI(query.id, form.value)
  } else {
    // 新建地址请求
    await postMemberAddressAPI(form.value)
  }
  // 成功提示
  uni.showToast({ icon: 'none', title: query.id ? '修改成功' : '添加成功' })
  // 返回上一页
  setTimeout(() => {
    uni.navigateBack()
  }, 500)
}

6.地址管理-表单校验

  1. uni-form组件
  2. 定义校验规则
// 定义校验规则
const rules: UniHelper.UniFormsRules = {
  receiver: {
    rules: [{ required: true, errorMessage: '请输入收货人姓名' }],
  },
  contact: {
    rules: [
      { required: true, errorMessage: '请输入联系方式' },
      { pattern: /^1[3-9]\d{9}$/, errorMessage: '手机号格式不正确' },
    ],
  },
  fullLocation: {
    rules: [{ required: true, errorMessage: '请输入所在地区' }],
  },
  address: {
    rules: [{ required: true, errorMessage: '请选择详细地址' }],
  },
}

  1. 修改表单结构
  2. 绑定表单数据
<uni-forms :rules="rules" :model="form" ref="formRef">
      <!-- 表单内容 -->
      <uni-forms-item name="receiver" class="form-item">
        <text class="label">收货人</text>
        <input class="input" placeholder="请填写收货人姓名" v-model="form.receiver" />
      </uni-forms-item>
      <uni-forms-item name="contact" class="form-item">
        <text class="label">手机号码</text>
        <input class="input" placeholder="请填写收货人手机号码" v-model="form.contact" />
      </uni-forms-item>
      <uni-forms-item name="fullLocation" class="form-item">
        <text class="label">所在地区</text>
        <picker
          class="picker"
          @change="onRegionChange"
          mode="region"
          :value="form.fullLocation.split(' ')"
        >
          <view v-if="form.fullLocation">{{ form.fullLocation }}</view>
          <view v-else class="placeholder">请选择省/市/区(县)</view>
        </picker>
      </uni-forms-item>
      <uni-forms-item name="address" class="form-item">
        <text class="label">详细地址</text>
        <input class="input" placeholder="街道、楼牌号等信息" v-model="form.address" />
      </uni-forms-item>
      <view class="form-item">
        <label class="label">设为默认地址</label>
        <switch
          class="switch"
          @change="onSwitchChange"
          color="#27ba9b"
          :checked="form.isDefault === 1"
        />
      </view>
    </uni-forms>
  1. 提交时校验
//表单组件实例
const formRef = ref<UniHelper.UniFormsInstance>()

// 提交表单
const onSubmit = async () => {
  try {
    await formRef.value?.validate?.()
    if (query.id) {
      // 修改地址
      await putMemberAddressByIdAPI(query.id, form.value)
    } else {
      // 新建地址请求
      await postMemberAddressAPI(form.value)
    }
    // 成功提示
    uni.showToast({ icon: 'none', title: query.id ? '修改成功' : '添加成功' })
    // 返回上一页
    setTimeout(() => {
      uni.navigateBack()
    }, 500)
  } catch (error) {
    uni.showToast({ icon: 'error', title: '请填写完整信息' })
  }
} 

7.删除收货地址

  1. 用uni-swipe-action组件
<!-- 地址列表 -->
    <scroll-view class="scroll-view" scroll-y>
      <view v-if="addressList.length" class="address">
        <uni-swipe-action class="address-list">
          <!-- 收货地址项 -->
          <uni-swipe-action-item class="item" v-for="item in addressList" :key="item.id">
            <view class="item-content">
              <view class="user">
                {{ item.receiver }}
                <text class="contact">{{ item.contact }}</text>
                <text v-if="item.isDefault" class="badge">默认</text>
              </view>
              <view class="locate">{{ item.fullLocation }} {{ item.address }}</view>
              <navigator
                class="edit"
                hover-class="none"
                :url="`/pagesMember/address-form/address-form?id=${item.id}`"
              >
                修改
              </navigator>
            </view>
            <!-- 右侧插槽 -->
            <template #right>
              <button @tap="onDeleteAddress(item.id)" class="delete-button">删除</button>
            </template>
          </uni-swipe-action-item>
        </uni-swipe-action>
      </view>
      <view v-else class="blank">暂无收货地址</view>
    </scroll-view>
  1. 修改列表结构
  2. 绑定删除事件
  3. 二次确认删除
// 删除
const onDeleteAddress = (id: string) => {
  // 二次确认
  uni.showModal({
    content: '确定删除?',
    success: async (res) => {
      if (res.confirm) {
        //删除API
        await deleteMemberAddressByIdAPI(id)
        // 重新获取收货地址列表
        // await async 确保先删除在重新获取
        getMemberAddressData()
      }
    },
  })
}
  1. 删除地址API
// 删除地址
export const deleteMemberAddressByIdAPI = (id: string) => {
  return http({
    method: 'DELETE',
    url: `/member/address/${id}`,
  })
}

8.SKU模块-基本概念

SKU概念:存货单位,库存管理的最小可用单元,通常称为‘单品’
SKU常见于电商领域,对于前端工程师而言,更多关注SKU算法,基于后端的SKU数据渲染页面并实现交互。

在uniapp插件市场中: https://ext.dcloud.net.cn/
搜索sku,并用vue3下载

  1. 将components目录下的vk-data-goods-sku-popup 和 vk-data-input-number-box 复制到你项目根目录下的components目录下 (若你的项目根目录下无components则先新增一个components目录)
  2. 通过下面的基本使用示例的方式使用组件,API文档 在最下面
<!-- 静态数据演示版本 适合任何后端 -->
<template>
    <view class="app">
        <button @click="openSkuPopup()">打开SKU组件</button>

        <vk-data-goods-sku-popup
            ref="skuPopup"
            v-model="skuKey"
            border-radius="20"
            :z-index="990"
            :localdata="goodsInfo"
            :mode="skuMode"
            @open="onOpenSkuPopup"
            @close="onCloseSkuPopup"
            @add-cart="addCart"
            @buy-now="buyNow"
        ></vk-data-goods-sku-popup>
    </view>
</template>

<script>
export default {
    data() {
        return {
            // 是否打开SKU弹窗
            skuKey: false,
            // SKU弹窗模式
            skuMode: 1,
            // 后端返回的商品信息
            goodsInfo: {}
        };
    },
    // 监听 - 页面每次【加载时】执行(如:前进)
    onLoad(options) {
        this.init(options);
    },
    methods: {
        // 初始化
        init(options = {}) {},
        // 获取商品信息,并打开sku弹出
        openSkuPopup() {
            /**
             * 获取商品信息
             * 这里可以看到每次打开SKU都会去重新请求商品信息,为的是每次打开SKU组件可以实时看到剩余库存
             */
            // 此处写接口请求,并将返回的数据进行处理成goodsInfo的数据格式,
            // goodsInfo是后端返回的数据
            this.goodsInfo = {
                "_id": "001",
                "name": "iphone11",
                "goods_thumb": "https://img14.360buyimg.com/n0/jfs/t1/59022/28/10293/141808/5d78088fEf6e7862d/68836f52ffaaad96.jpg",
                "sku_list": [
                    {
                        "_id": "001",
                        "goods_id": "001",
                        "goods_name": "iphone11",
                        "image": "https://img14.360buyimg.com/n0/jfs/t1/79668/22/9987/159271/5d780915Ebf9bf3f4/6a1b2703a9ed8737.jpg",
                        "price": 19800,
                        "sku_name_arr": ["红色", "128G", "公开版"],
                        "stock": 1000
                    },
                    {
                        "_id": "002",
                        "goods_id": "001",
                        "goods_name": "iphone11",
                        "image": "https://img14.360buyimg.com/n0/jfs/t1/52252/35/10516/124064/5d7808e0E46202391/7100f3733a1c1f00.jpg",
                        "price": 9800,
                        "sku_name_arr": ["白色", "256G", "公开版"],
                        "stock": 100
                    },
                    {
                        "_id": "003",
                        "goods_id": "001",
                        "goods_name": "iphone11",
                        "image": "https://img14.360buyimg.com/n0/jfs/t1/79668/22/9987/159271/5d780915Ebf9bf3f4/6a1b2703a9ed8737.jpg",
                        "price": 19800,
                        "sku_name_arr": ["红色", "256G", "公开版"],
                        "stock": 1
                    }
                ],
                "spec_list": [
                    {
                        "name": "颜色",
                        "list": [
                            { "name": "红色" },
                            { "name": "黑色" },
                            { "name": "白色" }
                        ]
                    },
                    {
                        "name": "内存",
                        "list": [
                            { "name": "128G" },
                            { "name": "256G" }
                        ],
                    },
                    {
                        "name": "版本",
                        "list": [
                            { "name": "公开版" },
                            { "name": "非公开版" }
                        ]
                    }
                ]
            };
            this.skuKey = true;
        },
        // sku组件 开始-----------------------------------------------------------
        onOpenSkuPopup() {
            console.log("监听 - 打开sku组件");
        },
        onCloseSkuPopup() {
            console.log("监听 - 关闭sku组件");
        },
        // 加入购物车前的判断
        addCartFn(obj) {
            let { selectShop } = obj;
            // 模拟添加到购物车,请替换成你自己的添加到购物车逻辑
            let res = {};
            let name = selectShop.goods_name;
            if (selectShop.sku_name != "默认") {
                name += "-" + selectShop.sku_name_arr;
            }
            res.msg = `${name} 已添加到购物车`;
            if (typeof obj.success == "function") obj.success(res);
        },
        // 加入购物车按钮
        addCart(selectShop) {
            console.log("监听 - 加入购物车");
            this.addCartFn({
                selectShop: selectShop,
                success: res => {
                    // 实际业务时,请替换自己的加入购物车逻辑
                    this.toast(res.msg);
                    setTimeout(() => {
                        this.skuKey = false;
                    }, 300);
                }
            });
        },
        // 立即购买
        buyNow(selectShop) {
            console.log("监听 - 立即购买");
            this.addCartFn({
                selectShop: selectShop,
                success: res => {
                    // 实际业务时,请替换自己的立即购买逻辑
                    this.toast("立即购买");
                }
            });
        },
        toast(msg) {
            uni.showToast({
                title: msg,
                icon: "none"
            });
        }
    }
};
</script>

<style lang="scss" scoped>
.app {
    padding: 30rpx;
    font-size: 28rpx;
}
</style>

eslint不报错

/* eslint-disable */

9.渲染商品信息

  1. SKU弹窗组件
<!-- Sku弹窗组件 -->
  <vk-data-goods-sku-popup v-model="isShowSku" :localdata="localdata" />
  1. SKU组件文档
  2. 类型声明文件
  3. 显示SKU弹窗
// 是否显示SKU组件
const isShowSku = ref(true)
// 商品信息
const localdata = ref({} as SkuPopupLocaldata)
  1. 渲染商品信息
// 获取商品详情信息
const goods = ref<GoodsResult>()
const getGoodsByIdData = async () => {
  const res = await getGoodsByIdAPI(query.id)
  goods.value = res.result
  // SKU组件所需格式
  localdata.value = {
    _id: res.result.id,
    name: res.result.name,
    goods_thumb: res.result.mainPictures[0],
    spec_list: res.result.specs.map((v) => {
      return {
        name: v.name,
        list: v.values,
      }
    }),
    sku_list: res.result.skus.map((v) => {
      return {
        _id: v.id,
        goods_id: res.result.id,
        goods_name: res.result.name,
        image: v.picture,
        price: v.price * 100, // 注意:需要乘以 100
        stock: v.inventory,
        sku_name_arr: v.specs.map((vv) => vv.valueName),
      }
    }),
  }
}

10. 打开弹窗交互

  1. 设置按钮模式
// 按钮模式
enum SkuMode {
  Both = 1,
  Cart = 2,
  Buy = 3,
}
const mode = ref<SkuMode>(SkuMode.Both)
// 打开Sku弹窗修改按钮模式
const openSkuPopup = (val: SkuMode) => {
  // 显示组件
  isShowSku.value = true
  // 修改按钮模式
  mode.value = val
}

  1. 微调组件样式
<!-- Sku弹窗组件 -->
  <vk-data-goods-sku-popup
    v-model="isShowSku"
    :localdata="localdata"
    :mode="mode"
    add-cart-background-color="#FFA868"
    buy-now-bankground-color="#27BA9B"
  />

 <view class="buttons">
      <view class="addcart" @tap="openSkuPopup(SkuMode.Cart)"> 加入购物车 </view>
      <view class="buynow" @tap="openSkuPopup(SkuMode.Buy)"> 立即购买 </view>
    </view>

11.计算被选中的值

  1. 获取SKU组件实例
  2. 计算被选中的值
//sku组件实例
const skuPopupRef = ref<SkuPopupInstanceType>()
// 计算被选中的值
const selectArrText = computed(() => {
  return skuPopupRef.value?.selectArr?.join(' ').trim() || '请选择获取商品'
})
  1. 渲染到页面
  2. 微调组件样式
  <!-- Sku弹窗组件 -->
  <vk-data-goods-sku-popup
    v-model="isShowSku"
    :localdata="localdata"
    :mode="mode"
    add-cart-background-color="#FFA868"
    buy-now-bankground-color="#27BA9B"
    ref="skuPopupRef"
    :actived-style="{
      color: '#27BA9B',
      borderColor: '#27BA9B',
      backgroundColor: '#E9F8F5',
    }"
  />

return skuPopupRef.value?.selectArr?.join(’ ').trim() || ‘请选择获取商品’, 要取出多余空格,否则短路运算会出问题

12.加入购物车

  1. 加入购物车事件
  <!-- Sku弹窗组件 -->
  <vk-data-goods-sku-popup
    v-model="isShowSku"
    :localdata="localdata"
    :mode="mode"
    add-cart-background-color="#FFA868"
    buy-now-bankground-color="#27BA9B"
    ref="skuPopupRef"
    :actived-style="{
      color: '#27BA9B',
      borderColor: '#27BA9B',
      backgroundColor: '#E9F8F5',
    }"
    @add-cart="onAddCart"
  />
  1. 调用API接口
import { http } from '@/utils/http'

export const postMemberCartAPI = (data: { skuId: string; count: number }) => {
  return http({
    method: 'POST',
    url: '/member/cart',
    data,
  })
}
  1. 成功提示
// 加入购物车
const onAddCart = async (ev: SkuPopupEvent) => {
  const res = await postMemberCartAPI({ skuId: ev._id, count: ev.buy_num })
  uni.showToast({ title: '添加成功' })
}
  1. 关闭SKU弹窗
// 加入购物车
const onAddCart = async (ev: SkuPopupEvent) => {
  const res = await postMemberCartAPI({ skuId: ev._id, count: ev.buy_num })
  uni.showToast({ title: '添加成功' })
  // 隐藏弹窗
  isShowSku.value = false
}

13.列表渲染

  1. 页面静态页面
  2. 获取会员store
import { useMemberStore } from '@/stores'
// 获取store
const MemberStore = useMemberStore()
  1. 条件渲染
    // 小程序多页面应用的更好的解决方案
    uni.navigateBack()
  1. 购物车列表API
export const getMemberCartAPI = () => {
  return http({
    method: 'GET',
    url: '/member/cart',
  })
}


// 获取购物车数据
const getMemberCartData = async () => {
  const res = await getMemberCartAPI()
}

  1. 初始化调用
// 初始化调用, 获取最新数据
onShow(() => {
  // 在onShow中要先判断
  if (MemberStore.profile) {
    getMemberCartData()
  }
})
  1. 列表渲染
<!-- 已登录: 显示购物车 -->
    <template v-if="MemberStore.profile">
      <!-- 购物车列表 -->
      <view class="cart-list" v-if="cartList.length">
        <!-- 优惠提示 -->
        <view class="tips">
          <text class="label">满减</text>
          <text class="desc">满1件, 即可享受9折优惠</text>
        </view>
        <!-- 滑动操作分区 -->
        <uni-swipe-action>
          <!-- 滑动操作项 -->
          <uni-swipe-action-item v-for="item in cartList" :key="item.skuId" class="cart-swipe">
            <!-- 商品信息 -->
            <view class="goods">
              <!-- 选中状态 -->
              <text class="checkbox" :class="{ checked: item.selected }"></text>
              <navigator
                :url="`/pages/goods/goods?id=${item.id}`"
                hover-class="none"
                class="navigator"
              >
                <image mode="aspectFill" class="picture" :src="item.picture"></image>
                <view class="meta">
                  <view class="name ellipsis">{{ item.name }}</view>
                  <view class="attrsText ellipsis"> {{ item.attrsText }}</view>
                  <view class="price">{{ item.nowPrice }}</view>
                </view>
              </navigator>
              <!-- 商品数量 -->
              <view class="count">
                <text class="text">-</text>
                <input class="input" type="number" :value="item.count.toString()" />
                <text class="text">+</text>
              </view>
            </view>
            <!-- 右侧删除按钮 -->
            <template #right>
              <view class="cart-swipe-right">
                <button class="button delete-button">删除</button>
              </view>
            </template>
          </uni-swipe-action-item>
        </uni-swipe-action>
      </view>

转换成字符串,避免类型报错
:value="item.count.toString()

14.删除单品

  1. 购物车删除API
export const deleteMemberCartAPI = (data: { ids: string[] }) => {
  return http({
    method: 'DELETE',
    url: '/member/cart',
    data,
  })
}

  1. 按钮绑定事件
<!-- 右侧删除按钮 -->
            <template #right>
              <view class="cart-swipe-right">
                <button class="button delete-button" @tap="onDeleteCart(item.skuId)">删除</button>
              </view>
            </template>
  1. 弹窗二次确认
  2. 调用删除API
  3. 重新获取列表
// 删除购物车
const deleteMemberCartData = async (skuId: string) => {
  const res = await deleteMemberCartAPI({ ids: [skuId] })
}

// 删除按钮
const onDeleteCart = (skuId: string) => {
  // 二次确认
  uni.showModal({
    content: '确认删除?',
    success: async (res) => {
      if (res.confirm) {
        // 后端调用删除
        await deleteMemberCartAPI({ ids: [skuId] })
        // 刷新
        deleteMemberCartData(skuId)
      }
    },
  })
}

15.修改单品数量

  1. 步进器组件
<vk-data-input-number-box
                  v-model="item.count"
                  :min="1"
                  :max="item.stock"
                  :index="item.skuId"
                  @change="onChangeCount"
                />
  1. 类型声明文件
  2. 属性绑定
  3. 事件绑定
  4. 调用单品修改API
export const putMemberCartBySkuIdAPI = (
  skuId: string,
  data: { selected?: boolean; count?: number },
) => {
  return http({
    method: 'PUT',
    url: `/member/cart/${skuId}`,
    data,
  })
}


// 修改商品数量
const onChangeCount = (ev: InputNumberBoxEvent) => {
  putMemberCartBySkuIdAPI(ev.index, { count: ev.value })
}

16.修改选中状态

  1. 点击单品选中
  2. 调用修改单品选中API
// 修改选中状态-单品修改
const onChangeSelected = (item: CartItem) => {
  // 前端数据更新
  item.selected = !item.selected
  // 后端数据更新
  putMemberCartBySkuIdAPI(item.skuId, { selected: item.selected })
}
  1. 计算全选状态
//计算全选中状态
const isSelectedAll = computed(() => {
  // 问一下看是否每一项都符合要求
  return cartList.value.length && cartList.value.every((v) => v.selected)
})
  1. 点击全选选中
// 修改选中状态-全选修改
const onChangeSelectedAll = () => {
  // 全选状态取反
  const _isSelectedAll = !isSelectedAll.value
  // 前端更新
  cartList.value.forEach((item) => {
    item.selected = _isSelectedAll
  })
  // 后端更新
}
  1. 调用修改全选状态API
export const putMemberCartSelectedAPI = (data: { selected: boolean }) => {
  return http({
    method: 'PUT',
    url: '/member/cart/selected',
    data,
  })
}

// 修改选中状态-全选修改
const onChangeSelectedAll = () => {
  // 全选状态取反
  const _isSelectedAll = !isSelectedAll.value
  // 前端更新
  cartList.value.forEach((item) => {
    item.selected = _isSelectedAll
  })
  // 后端更新
  putMemberCartSelectedAPI({ selected: _isSelectedAll })
}

17.底部结算信息

  1. 计算选中单品列表
// 计算选中单品列表
const selectedCartList = computed(() => {
  return cartList.value.filter((v) => v.selected)
})
  1. 计算选中总件数
//计算选中总件数
const selectedCartListCount = computed(() => {
  return selectedCartList.value.reduce((sum, item) => sum + item.count, 0)
})
  1. 计算选中总总金额
//计算选中总金额
const selectedCartListMoney = computed(() => {
  return selectedCartList.value
    .reduce((sum, item) => sum + item.count * item.nowPrice, 0)
    .toFixed(2)
})
  1. 结算按钮交互
// 结算按钮
//没有选中商品再进行提醒
const gotoPayment = () => {
  if (selectedCartListCount.value === 0) {
    // return 终止后面的程序
    return uni.showToast({
      icon: 'none',
      title: '请选择商品',
    })
  }
  // 跳转到结算页
  uni.showToast({ title: '等待完成' })
}

<!-- 吸底工具栏 -->
      <view class="toolbar">
        <text @tap="onChangeSelectedAll" class="all" :class="{ checked: isSelectedAll }">全选</text>
        <text class="text">合计:</text>
        <text class="amount">{{ selectedCartListMoney }}</text>
        <view class="button-grounp">
          <view
            @tap="gotoPayment"
            class="button payment-button"
            :class="{ disabled: selectedCartListCount === 0 }"
          >
            去结算({{ selectedCartListCount }})
          </view>
        </view>
      </view>

18.两个购物车页面

在这里插入图片描述
在pages.json中的list 中指定的是开发页,没有的就不是

<script lang="ts">
import CartMain from './components/CartMain.vue'
</script>

<template>
  <CartMain />
</template>


网站公告

今日签到

点亮在社区的每一天
去签到