doc.md 14 KB

Sku 商品规格选择

介绍

按需加载请加载对应依赖组件:Popup、InputNumber、Price

安装

import { createApp } from 'vue';
//vue
import { Sku, Popup, InputNumber, Price } from '@nutui/nutui';
//taro
import { Sku, Popup, InputNumber, Price } from '@nutui/nutui-taro';

const app = createApp();
app.use(Sku);
app.use(Popup);
app.use(InputNumber);
app.use(Price);

代码演示

基础用法

<nut-sku
  v-model:visible="base"
  :sku="sku"
  :goods="goods"
  @selectSku="selectSku"
  @clickBtnOperate="clickBtnOperate"
  @close="close"
></nut-sku>
setup() {
    const base = ref(false);
    const data = reactive({
      sku: [
          // 具体数据结构见下方文档
        ],
      goods: {
          // 具体数据结构见下方文档
        }
    });

    onMounted(() => {});
    // 切换规格类目
    const selectSku = (ss: string) => {
      const { sku, skuIndex, parentSku, parentIndex } = ss;
      if (sku.disable) return false;
      data.sku[parentIndex].list.forEach((s) => {
        s.active = s.id == sku.id;
      });
      data.goods = {
        skuId: sku.id,
        price: '4599.00',
        imagePath:
          '//img14.360buyimg.com/n4/jfs/t1/215845/12/3788/221990/618a5c4dEc71cb4c7/7bd6eb8d17830991.jpg' 
      };
    };
    // 底部操作按钮触发
    const clickBtnOperate = (op:string)=>{
      console.log('点击了操作按钮',op)
    } 
    // 关闭商品规格弹框
    const close = ()=>{}
    return { base, selectSku, clickBtnOperate,close, ...toRefs(data) };
}

不可售

<nut-sku
  v-model:visible="notSell"
  :sku="skuData"
  :goods="goodsInfo"
  :btnExtraText="btnExtraText"
  @changeStepper="changeStepper"
  @selectSku="selectSku"
  @close="close"
>
  <template #sku-operate>
    <div class="sku-operate-box">
      <nut-button class="sku-operate-box-dis" type="warning">查看相似商品</nut-button>
      <nut-button class="sku-operate-box-dis" type="info">到货通知</nut-button>
    </div>
  </template>
</nut-sku>
setup() {
    const notSell = ref(false);
    const data = reactive({
      sku: [
          // 数据结构见下方文档
        ],
      goods: {
          // 数据结构见下方文档
        }
    });

    const btnExtraText = ref('抱歉,此商品在所选区域暂无存货');
    // inputNumber 更改
    const changeStepper = (count: number) => {
      console.log('购买数量', count);
    };

    // 切换规格类目
    const selectSku = (ss: string) => {
      const { sku, skuIndex, parentSku, parentIndex } = ss;
      if (sku.disable) return false;
      data.sku[parentIndex].list.forEach((s) => {
        s.active = s.id == sku.id;
      });
      data.goods = {
        skuId: sku.id,
        price: '4599.00',
        imagePath:
          '//img14.360buyimg.com/n4/jfs/t1/216079/14/3895/201095/618a5c0cEe0b9e2ba/cf5b98fb6128a09e.jpg' 
      };
    };
    // 底部操作按钮触发
    const clickBtnOperate = (op:string)=>{
      console.log('点击了操作按钮',op)
    } 
    return { notSell, changeStepper,selectSku,btnExtraText,...toRefs(data) };
}
.sku-operate-box {
  width: 100%;
  display: flex;
  padding: 8px 10px;
  box-sizing: border-box;

  .sku-operate-box-dis{
    width: 100%;
    flex-shrink: 1;
    &:first-child{
      margin-right: 18px;
    }
  }
}

自定义步进器

可以按照需求配置数字输入框的最大值、最小值、文案等

<nut-sku
  v-model:visible="customStepper"
  :sku="sku"
  :goods="goods"
  :showSaleLimit="true"
  :stepperMax="7"
  :stepperMin="2"
  :stepperExtraText="stepperExtraText"
  @changeStepper="changeStepper"
  @overLimit="overLimit"
  :btnOptions="['buy', 'cart']"
  @selectSku="selectSku"
  @clickBtnOperate="clickBtnOperate"
  @close="close"
></nut-sku>
setup() {
    const customStepper = ref(false);
    const data = reactive({
      sku: [
          // 数据结构见下方文档
        ],
      goods: {
          // 数据结构见下方文档
        }
    });

    const stepperExtraText = () => {
      return `<div style="width:100%;text-align:right;color:#F00">2 件起售</div>`
    };
    // inputNumber 更改
    const changeStepper = (count: number) => {
      console.log('购买数量', count);
    };

    // inputNumber 极限值
    const overLimit = (val: any) => {
      if (val.action == 'reduce') {
        Toast.text(`至少买${val.value}件哦`);
      } else {
        Toast.text(`最多买${val.value}件哦`);
      }
    };
    // 切换规格类目
    const selectSku = (ss: string) => {
      const { sku, skuIndex, parentSku, parentIndex } = ss;
      if (sku.disable) return false;
      data.sku[parentIndex].list.forEach((s) => {
        s.active = s.id == sku.id;
      });
      data.goods = {
        skuId: sku.id,
        price: '4599.00',
        imagePath:
          '//img14.360buyimg.com/n4/jfs/t1/215845/12/3788/221990/618a5c4dEc71cb4c7/7bd6eb8d17830991.jpg' 
      };
    };
    // 底部操作按钮触发
    const clickBtnOperate = (op:string)=>{
      console.log('点击了操作按钮',op)
    } 
    return { overLimit, changeStepper,selectSku, clickBtnOperate,stepperExtraText,...toRefs(data) };
}

自定义插槽

Sku 组件默认划分为若干区域,这些区域都定义成了插槽,可以按照需求进行替换。

<nut-sku
    v-model:visible="customBySlot"
    :sku="sku"
    :goods="goods"
    :btnOptions="['buy', 'cart']"
    @selectSku="selectSku"
    @clickBtnOperate="clickBtnOperate"
    @close="close()"
>
    <!-- 商品展示区,价格区域 -->
    <template #sku-header-price>
        <div>
            <nut-price :price="goodsInfo.price" :needSymbol="true" :thousands="false"> </nut-price>
            <span class="tag"></span>
        </div>
    </template> 
    <!-- 商品展示区,编号区域 -->
    <template #sku-header-extra>
        <span class="nut-sku-header-right-extra">重量:0.1kg  编号:{{skuId}}  </span>
    </template> 
    <!-- sku 展示区上方与商品信息展示区下方区域,无默认展示内容 -->
    <template #sku-select-top>
        <div class="address">
            <nut-cell style="box-shadow:none;padding:13px 0" title="送至" :desc="addressDesc" @click="showAddressPopup=true"></nut-cell>
        </div>
    </template>
    <!-- 底部按钮操作区 -->
    <template #sku-operate>
        <div class="sku-operate-box">
        <nut-button class="sku-operate-item" shape="square" type="warning">加入购物车</nut-button>
        <nut-button class="sku-operate-item" shape="square" type="primary">立即购买</nut-button>
        </div>
    </template>
</nut-sku>

<nut-address
  v-model:visible="showAddressPopup"
  type="exist"
  :exist-address="existAddress"
  @close="close"
  :is-show-custom-address="false"
  @selected="selectedAddress"
  exist-address-title="配送至"
></nut-address>
setup() {
    const customBySlot = ref(false);
    const showAddressPopup = ref(false);
    const data = reactive({
      sku: [
          // 数据结构见下方文档
        ],
      goods: {
          // 数据结构见下方文档
        }
    });
    const addressDesc = ref('(配送地会影响库存,请先确认)');
    const existAddress = ref([
      {
        id: 1,
        addressDetail: 'th ',
        cityName: '石景山区',
        countyName: '城区',
        provinceName: '北京',
        selectedAddress: true,
        townName: ''
      },
      {
        id: 2,
        addressDetail: '12 ',
        cityName: '电饭锅',
        countyName: '扶绥县',
        provinceName: '北京',
        selectedAddress: false,
        townName: ''
      },
      {
        id: 3,
        addressDetail: '发大水比 ',
        cityName: '放到',
        countyName: '广宁街道',
        provinceName: '钓鱼岛全区',
        selectedAddress: false,
        townName: ''
      },
      {
        id: 4,
        addressDetail: '还是想吧百度吧 ',
        cityName: '研发',
        countyName: '八里庄街道',
        provinceName: '北京',
        selectedAddress: false,
        townName: ''
      }
    ]);

    // 切换规格类目
    const selectSku = (ss: string) => {
      const { sku, skuIndex, parentSku, parentIndex } = ss;
      if (sku.disable) return false;
      data.sku[parentIndex].list.forEach((s) => {
        s.active = s.id == sku.id;
      });
      data.goods = {
        skuId: sku.id,
        price: '6002.10',
        imagePath:
          '//img14.360buyimg.com/n4/jfs/t1/215845/12/3788/221990/618a5c4dEc71cb4c7/7bd6eb8d17830991.jpg' 
      };
    };
    const selectedAddress = (prevExistAdd: any, nowExistAdd: any) => {
      const { provinceName, countyName, cityName } = nowExistAdd;
      addressDesc.value = `${provinceName}${countyName}${cityName}`;
    };
    // 底部操作按钮触发
    const clickBtnOperate = (op:string)=>{
      console.log('点击了操作按钮',op)
    } 
    return { customBySlot, selectSku, clickBtnOperate,existAddress,addressDesc,selectedAddress,...toRefs(data) };
}

API

Props

参数 说明 类型 默认值
v-model:visible 是否显示商品规格弹框 boolean false
sku 商品 sku 数据 Array []
goods 商品信息 Object -
stepper-max 设置 inputNumber 最大值 [String, Number] 99999
stepper-min 设置 inputNumber 最小值 [String, Number] 1
btn-options 底部按钮设置。['confirm','buy','cart' ] 分别对应确定、立即购买、加入购物车 Array ['confirm']
btn-extra-text 按钮上部添加文案,默认为空,有值时显示 String -
stepper-title 数量选择组件左侧文案 String '购买数量'
stepper-extra-text inputNumber 与标题之间的文案 [Function, false] false
buy-text 立即购买按钮文案 String 立即购买
add-cart-text 加入购物车按钮文案 String 加入购物车
confirm-text 确定按钮文案 String 确定

Events

事件名 说明 回调参数
select-sku 切换规格类目时触发 {sku,skuIndex,parentSku,parentIndex}
add inputNumber 点击增加按钮时触发 value
reduce inputNumber 点击减少按钮时触发 value
overLimit inputNumber 点击不可用的按钮时触发 value
change-stepper 购买变化时触发 value
click-btn-operate 点击底部按钮时触发 {type:'confirm',value:'inputNumber value'}
click-close-icon 点击左上角关闭 icon 时触发 -
click-overlay 点击遮罩时触发 -
close 关闭弹层时触发 -

Slots

Sku 组件默认划分为若干区域,这些区域都定义成了插槽,可以按照需求进行替换。

| 事件名 | 说明 | |--------|----------------| | sku-header | 商品信息展示区,包含商品图片、价格、编号 | | sku-header-price | 商品信息展示区,价格区域展示| | sku-header-extra | 商品信息展示区,编号区域展示 | | sku-select-top | sku 展示区上方与商品信息展示区下方区域,无默认展示内容 | | sku-select | sku 展示区 | | sku-stepper | 数量选择区 | | sku-stepper-bottom | 数量选择区下方区域 | | sku-operate | 底部按钮操作区域 |

goods 对象结构

goods:{
    skuId:'', // 商品信息展示区,商品编号
    price: "0", // 商品信息展示区,商品价格
    imagePath: "", // 商品信息展示区,商品图
}

sku 数组结构

sku 数组中,每一个数组索引代表一个规格类目。其中,list 代表该规格类目下的类目值。每个类目值对象包括:name、id、active(是否选中)、disable(是否可选)

sku : [{
    id: 1,
    name: '颜色',
    list: [{
        name: '亮黑色',
        id: 100016015112,
        active: true,
        disable: false
      },
      {
        name: '釉白色',
        id: 100016015142,
        active: false,
        disable: false
      },
      {
        name: '秘银色',
        id: 100016015078,
        active: false,
        disable: false
      },
      {
        name: '夏日胡杨',
        id: 100009064831,
        active: false,
        disable: false
      },
      {
        name: '秋日胡杨',
        id: 100009064830,
        active: false,
        disable: false
      }
    ]
  },
  {
    id: 2,
    name: '版本',
    list: [{
        name: '8GB+128GB',
        id: 100016015102,
        active: true,
        disable: false
      },
      {
        name: '8GB+256GB',
        id: 100016015122,
        active: false,
        disable: false
      }
    ]
  },
  {
    id: 3,
    name: '版本',
    list: [{
        name: '4G(有充版)',
        id: 100016015103,
        active: true,
        disable: false
      },
      {
        name: '5G(有充版)',
        id: 100016015123,
        active: false,
        disable: false
      },
      {
        name: '5G(无充版)',
        id: 100016015104,
        active: true,
        disable: true
      },
      {
        name: '5G(无充)质保换新版',
        id: 100016015125,
        active: false,
        disable: false
      }
    ]
  }
];