uniapp项目之小兔鲜儿小程序商城(七) 商品详情页(登录后):加入购物车,立即购买(SKU 模块)

一.商品详情页

对于登录后的商品详情页,需要处理的业务有:
加入购物车,立即购买(SKU 模块)

1.SKU模块

学会使用插件市场,下载并使用 SKU 组件,实现商品详情页规格展示和交互。

  • 什么是SKU?
存货单位(Stock Keeping Unit),库存管理的最小可用单元,通常称为“单品”。
SKU 常见于电商领域,对于前端工程师而言,更多关注 SKU 算法 和 用户交互体验。

在这里插入图片描述

  • 什么是插件市场?
uni-app 插件市场,是 uni-app 官方插件生态集中地。
SKU 属于电商常见业务,插件市场有现成的 SKU 插件,搜索SKU,找支持vue3的插件来使用即可

在这里插入图片描述

1.1.下载SKU插件
  • step1:登录后在插件市场中下载vk-data-goods-sku-popup插件
  • step2:把uni-modules>vk-data-goods-sku-popup>components文件夹下的两个组件(文件夹)复制到本地项目的components文件夹下
  • step3:复制示例代码到项目中随便一个vue空白页面中验证效果

思考:全程没有引入为何能直接使用成功?
答:在pages.json"easycom"设置了autoscan'':true,会自动扫描components文件夹

1.2.引入组件

引入vk-data-goods-sku-popup弹窗组件

  <!-- SKU弹窗组件 -->
  <vk-data-goods-sku-popup v-model="isShowSku" :localdata="localdata" />
  <!-- 弹窗测试 -->
  <button @tap="isShowSku = true">打开 SKU 弹窗</button>
1.3.类型声明

基于文档,自定义一个类型声明文件components/vk-data-goods-sku-popup/vk-data-goods-sku-popup.d.ts

import {
   
    Component } from '@uni-helper/uni-app-types'
/** SKU 弹出层 */
export type SkuPopup = Component<SkuPopupProps>
/** SKU 弹出层实例 */
export type SkuPopupInstance = InstanceType<SkuPopup>
/** SKU 弹出层属性 */
export type SkuPopupProps = {
   
   
  /** 双向绑定,true 为打开组件,false 为关闭组件 */
  modelValue: boolean
  /** 商品信息本地数据源 */
  localdata: SkuPopupLocaldata
  /** 按钮模式 1:都显示 2:只显示购物车 3:只显示立即购买 */
  mode?: 1 | 2 | 3
  /** 该商品已抢完时的按钮文字 */
  noStockText?: string
  /** 库存文字 */
  stockText?: string
  /** 点击遮罩是否关闭组件 */
  maskCloseAble?: boolean
  /** 顶部圆角值 */
  borderRadius?: string | number
  /** 最小购买数量 */
  minBuyNum?: number
  /** 最大购买数量 */
  maxBuyNum?: number
  /** 每次点击后的数量 */
  stepBuyNum?: number
  /** 是否只能输入 step 的倍数 */
  stepStrictly?: boolean
  /** 是否隐藏库存的显示 */
  hideStock?: false
  /** 主题风格 */
  theme?: 'default' | 'red-black' | 'black-white' | 'coffee' | 'green'
  /** 默认金额会除以100(即100=1元),若设置为0,则不会除以100(即1=1元) */
  amountType?: 1 | 0
  /** 自定义获取商品信息的函数(已知支付宝不支持,支付宝请改用localdata属性) */
  customAction?: () => void
  /** 是否显示右上角关闭按钮 */
  showClose?: boolean
  /** 关闭按钮的图片地址 */
  closeImage?: string
  /** 价格的字体颜色 */
  priceColor?: string
  /** 立即购买 - 按钮的文字 */
  buyNowText?: string
  /** 立即购买 - 按钮的字体颜色 */
  buyNowColor?: string
  /** 立即购买 - 按钮的背景颜色 */
  buyNowBackgroundColor?: string
  /** 加入购物车 - 按钮的文字 */
  addCartText?: string
  /** 加入购物车 - 按钮的字体颜色 */
  addCartColor?: string
  /** 加入购物车 - 按钮的背景颜色 */
  addCartBackgroundColor?: string
  /** 商品缩略图背景颜色 */
  goodsThumbBackgroundColor?: string
  /** 样式 - 不可点击时,按钮的样式 */
  disableStyle?: object
  /** 样式 - 按钮点击时的样式 */
  activedStyle?: object
  /** 样式 - 按钮常态的样式 */
  btnStyle?: object
  /** 字段名 - 商品表id的字段名 */
  goodsIdName?: string
  /** 字段名 - sku表id的字段名 */
  skuIdName?: string
  /** 字段名 - 商品对应的sku列表的字段名 */
  skuListName?: string
  /** 字段名 - 商品规格名称的字段名 */
  specListName?: string
  /** 字段名 - sku库存的字段名 */
  stockName?: string
  /** 字段名 - sku组合路径的字段名 */
  skuArrName?: string
  /** 字段名 - 商品缩略图字段名(未选择sku时) */
  goodsThumbName?: string
  /** 被选中的值 */
  selectArr?: string[]
  /** 打开弹出层 */
  onOpen: () => void
  /** 关闭弹出层 */
  onClose: () => void
  /** 点击加入购物车时(需选择完SKU才会触发)*/
  onAddCart: (event: SkuPopupEvent) => void
  /** 点击立即购买时(需选择完SKU才会触发)*/
  onBuyNow: (event: SkuPopupEvent) => void
}
/**  商品信息本地数据源 */
export type SkuPopupLocaldata = {
   
   
  /** 商品 ID */
  _id: string
  /** 商品名称 */
  name: string
  /** 商品图片 */
  goods_thumb: string
  /** 商品规格列表 */
  spec_list: SkuPopupSpecItem[]
  /** 商品SKU列表 */
  sku_list: SkuPopupSkuItem[]
}
/** 商品规格名称的集合 */
export type SkuPopupSpecItem = {
   
   
  /** 规格名称 */
  name: string
  /** 规格集合 */
  list: {
   
    name: string }[]
}
/** 商品SKU列表 */
export type SkuPopupSkuItem = {
   
   
  /** SKU ID */
  _id: string
  /**  商品 ID */
  goods_id: string
  /** 商品名称 */
  goods_name: string
  /** 商品图片 */
  image: string
  /** SKU 价格 * 100, 注意:需要乘以 100 */
  price: number
  /** SKU 规格组成, 注意:需要与 spec_list 数组顺序对应 */
  sku_name_arr: string[]
  /** SKU 库存 */
  stock: number
}
/** 当前选择的sku数据 */
export type SkuPopupEvent = SkuPopupSkuItem & {
   
   
  /** 商品购买数量 */
  buy_num: number
}
/** 全局组件类型声明 */
declare module 'vue' {
   
   
  export interface GlobalComponents {
   
   
    'vk-data-goods-sku-popup': SkuPopup//注册弹窗组件
  }
}
1.4.显示sku弹窗

在这里插入图片描述

使用以下两个属性:

  • localdata 绑定商品 SKU 数据来源
  • v-model 双向绑定,显示/隐藏组件

注意:后端返回的数据格式和插件所需的格式不一致,需按插件要求进行处理。

在商品详情页goods.vue中显示SKU弹窗

<script setup lang="ts">
import type {
   
    SkuPopupLocaldata } from '@/components/vk-data-goods-sku-popup/vk-data-goods-sku-popup'
// 是否显示SKU组件
const isShowSku = ref(false)
//商品信息
const localdata = ref({
   
   } as SkuPopupLocaldata)
// 获取商品详情信息
const goods = ref<GoodsResult>()
const getGoodsByIdData = async () => {
   
   
  const res = await getGoodsByIdAPI(query.id)
  goods.value = res.result

  // SKU组件所需格式
  localdata.value = {
   
   
    _id: res.result.id, //当前商品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),
      }
    }),
  }
}
</script>
<template>
  <!-- SKU弹窗组件 -->
  <vk-data-goods-sku-popup v-model="isShowSku" :localdata="localdata" />
  <!-- 弹窗测试 -->
  <button @tap="isShowSku = true">打开 SKU 弹窗</button>
</template>
</script>
1.5 弹窗打开时的业务交互

在这里插入图片描述

SKU 弹窗的按钮有三种形式:

    1.点击选择:弹出窗有加入购物车和立即购买
    2.点击加入购物车:弹出窗只显示sku和底部的加入购物车
    3.点击立即购买:弹出窗只显示sku和底部的立即购买

如何实现?

step1:打开sku弹窗
step2:设置按钮模式
step3:微调组件样式

代码:

<script setup lang="ts">
// 枚举类型:设置按钮模式,映射更有语义的名称(Both,Cart,Buy)
enum SkuMode {
   
   
  Both = 1,
  Cart = 2,
  Buy = 3,
}
const mode = ref<SkuMode>(SkuMode.Cart)
// 封装一个方法:打开SKU弹窗修改按钮模式
// step1:打开sku弹窗
const openSkuPopup = (val: SkuMode) => {
   
   
  // 显示SKU弹窗
  isShowSku.value = true
  // step2:修改按钮模式
  mode.value = val
}
</script>
<template>
   <!-- SKU弹窗组件 -->
   <!-- step3:微调组件样式 -->
  <vk-data-goods-sku-popup
    v-model="isShowSku"
    :localdata="localdata"
    :mode="mode"
    add-cart-background-color="#FFA868"
    buy-now-background-color="#27BA9B"
  />

      <!-- 操作面板 -->
      <view class="action">
        <view @tap="openSkuPopup(SkuMode.Both)" class="item arrow">
          <text class="label">选择</text>
          <text class="text ellipsis"> {
   
   {
   
    selectArrText }} </text>
        </view>
        ......
     </view>

    ......
    <view class="buttons">
      <view @tap="openSkuPopup(SkuMode.Cart)" class="addcart"> 加入购物车 </view>
      <view @tap="openSkuPopup(SkuMode.Buy)" class="payment"> 立即购买 </view>
    </view>
</template
### 商品详情的设计思路 在基于 Vue3 实现的电商项目小兔鲜儿”中,商品详情是用户深入了解商品信息、进行购买决策的重要界面。设计上需要兼顾用户体验与功能完整性,同时结合现代前端框架的优势实现高效开发。 #### 数据展示与交互 1. **商品信息展示**:面核心部分包括商品图片轮播、基本信息(名称、价格、库存等)、规格参数、商品描述等内容。这些数据通常通过接口从后端获取,并利用 Vue 的响应式特性进行渲染。 2. **图片懒加载**:为了优化性能,提升首屏加载速度,使用了自定义指令配合 `IntersectionObserver` 技术实现了图片懒加载机制[^4]。只有当图片进入视口区域时才开始加载,有效减少了初始请求量。 3. **规格选择**:提供 SKU(Stock Keeping Unit)管理功能,允许用户根据需求选择不同的商品属性组合(如颜色、尺寸),并实时更新对应的价格和库存状态。 #### 购物车集成 1. **加入购物车逻辑**:用户可以选择商品数量并点击“加入购物车”。此操作会触发一个方法,检查当前用户是否登录以及是否已存在相同 SKU 的商品条目。如果已登录,则调用 API 将商品添加至服务器端购物车;若未登录,则将商品信息保存到本地存储(Pinia 状态管理库)中。 2. **退出清空策略**:当用户执行登出操作时,应清除 Pinia 中保存的所有购物车数据以避免混淆,确保下次登录后能够正确同步云端购物车记录[^1]。 ### 具体实现方案 #### 面结构搭建 采用组件化开发模式构建商品详情,主要包含以下几个关键组件: - **布局组件** (`Layout`):负责整个面的基础框架搭建,例如顶部导航栏 (`LayoutNav`)、头部标题区 (`LayoutHeader`) 和底部版权信息栏 (`LayoutFooter`)- **商品展示组件**:专注于呈现商品主图、副图及详细参数列表。 - **规格选项组件**:用于处理用户的规格选择行为,并动态计算最终售价。 - **操作按钮组件**:集成“立即购买”、“加入购物车”等功能性按钮。 ```vue <template> <LayoutNav /> <LayoutHeader /> <!-- 二级路由出口区域 --> <RouterView /> <LayoutFooter /> </template> <script setup> import LayoutNav from &#39;./components/LayoutNav.vue&#39; import LayoutHeader from &#39;./components/LayoutHeader.vue&#39; import LayoutFooter from &#39;./components/LayoutFooter.vue&#39; </script> ``` #### 状态管理和持久化 使用 Pinia 作为全局状态管理工具来维护购物车相关数据。对于每个新增的商品条目,先尝试在现有购物车列表中查找是否存在相同的 SKU ID;若存在则增加其计数器值,否则直接将其推入数组末尾。 ```javascript // src/stores/cart.js import { ref } from &#39;vue&#39; import { defineStore } from &#39;pinia&#39; export const useCartStore = defineStore(&#39;cart&#39;, () => { const cartList = ref([]) function addCart(goods) { const item = cartList.value.find(item => goods.skuId === item.skuId) if (item) { item.count++ } else { cartList.value.push(goods) } } return { cartList, addCart } }, { persist: true }) ``` #### 登录状态检测 通过检查会员模块中的 token 字段是否存在来判断用户是否已经成功登录系统。这一机制广泛应用于所有涉及敏感操作的地方(比如访问个人中心或修改订单详情),从而保障系统的安全性。 ```javascript // 示例代码 - 检查token是否存在 function checkLoginStatus() { const memberToken = localStorage.getItem(&#39;member_token&#39;) return !!memberToken } ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端OnTheRun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值