# Sku 商品规格选择 ### 介绍 按需加载请加载对应依赖组件:Popup、InputNumber、Price ### 安装 ``` javascript 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); ``` ## 代码演示 ### 基础用法 ```html ``` ```javascript 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) }; } ``` ### 不可售 ```html ``` ```javascript 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) }; } ``` ```css .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; } } } ``` ### 自定义步进器 可以按照需求配置数字输入框的最大值、最小值、文案等 ```html ``` ```javascript setup() { const customStepper = ref(false); const data = reactive({ sku: [ // 数据结构见下方文档 ], goods: { // 数据结构见下方文档 } }); const stepperExtraText = () => { return `
2 件起售
` }; // 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 组件默认划分为若干区域,这些区域都定义成了插槽,可以按照需求进行替换。 ```html ``` ```javascript 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 对象结构 ```javascript goods:{ skuId:'', // 商品信息展示区,商品编号 price: "0", // 商品信息展示区,商品价格 imagePath: "", // 商品信息展示区,商品图 } ``` ### sku 数组结构 sku 数组中,每一个数组索引代表一个规格类目。其中,list 代表该规格类目下的类目值。每个类目值对象包括:name、id、active(是否选中)、disable(是否可选) ```javascript 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 } ] } ]; ```