sku商品选择的算法实现

不啰嗦了,直接上代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Sku 多维属性状态判断</title>
    <script src="http://misc.360buyimg.com/jdf/lib/jquery-1.6.4.js"></script>
    <style>
        body {
            font-size: 12px;
        }
        dt {
            width: 100px;
            text-align: right;
        }
        dl {
            clear: both;
            overflow:hidden;
        }
        dl.hl {
            background:#ddd;
        }
        dt, dd {
            float:left;
            height: 40px;
            line-height: 40px;
            margin-left: 10px;
        }
        button {
            font-size: 14px;
            font-weight: bold;
            padding: 4px 4px;
        }
        .disabled {
            color:#999;
            border: 1px dashed #666;
        }
        .active {
            color: red;
        }
    </style>
</head>
<body>

<p>
    <textarea id="data_area" cols="100" rows="10">
[
   { "颜色": "红", "尺码": "大", "型号": "A", "skuId": "3158055" },
   { "颜色": "白", "尺码": "大", "型号": "A", "skuId": "3158054" },
   { "颜色": "白", "尺码": "中", "型号": "B", "skuId": "3133859" },
   { "颜色": "蓝", "尺码": "小", "型号": "C", "skuId": "3516833" }
]
    </textarea>
</p>
<p>
    <input onclick="updateData()" type="button" value="更新数据">
</p>

<hr>

<div id="app"></div>

<hr>

<div id="msg"></div>

<script>
var data = JSON.parse($('#data_area').val())

var res = {}
/*
res = {
        "": { "skus": ["3158055","3158054","3133859","3516833"] },
        "红": { "skus": ["3158055"] },
        "大": { "skus": ["3158055","3158054"] },
        "红⊙大": { "skus": ["3158055"] },
        "A": { "skus": ["3158055","3158054"] },
        "红⊙A": { "skus": ["3158055"] },
        "大⊙A": { "skus": ["3158055","3158054"] },
        "红⊙大⊙A": { "skus": ["3158055"] },
        "白": { "skus": ["3158054","3133859"] },
        "白⊙大": { "skus": ["3158054"] },
        "白⊙A": { "skus": ["3158054"] },
        "白⊙大⊙A": { "skus": ["3158054"] },
        "中": { "skus": ["3133859"] },
        "白⊙中": { "skus": ["3133859"] },
        "B": { "skus": ["3133859"] },
        "白⊙B": { "skus": ["3133859"] },
        "中⊙B": { "skus": ["3133859"] },
        "白⊙中⊙B": { "skus": ["3133859"] },
        "蓝": { "skus": ["3516833"] },
        "小": { "skus": ["3516833"] },
        "蓝⊙小": { "skus": ["3516833"] },
        "C": { "skus": ["3516833"] },
        "蓝⊙C": { "skus": ["3516833"] },
        "小⊙C": { "skus": ["3516833"] },
        "蓝⊙小⊙C": { "skus": ["3516833"] }
    }
*/

var spliter = '\u2299'  // '\u2299'是unicode码,转义后是⊙
var r = {}
var keys = []  // sku中的各个属性
var selectedCache = []

/**
 * 计算组合数据
 */
function combineAttr(data, keys) {
    console.log("combineAttr", data, keys)
    var allKeys = []
    var result = {}
    /*
    allKeys: [{path: '红⊙大⊙A', sku: '3158055'}
            {path: '白⊙大⊙A', sku: '3158054'}
            {path: '白⊙中⊙B', sku: '3133859'}
            {path: '蓝⊙小⊙C', sku: '3516833'}]
    result: {
            "型号": ['A', 'B', 'C']
            "尺码": ['大', '中', '小']
            "颜色": ['红', '白', '蓝']
            }           
    */

    for (var i = 0; i < data.length; i++) {
        var item = data[i]  // item = { "颜色": "红", "尺码": "大", "型号": "A", "skuId": "3158055" }
        var values = []  // values = ["红", "大", "A"]

        for (var j = 0; j < keys.length; j++) {
            var key = keys[j]  // key = 颜色
            if (!result[key]) result[key] = []
            if (result[key].indexOf(item[key]) < 0) result[key].push(item[key])
            values.push(item[key])
        }
        allKeys.push({
            path: values.join(spliter),
            sku: item['skuId']
        })
    }
    return {
        result: result,
        items: allKeys
    }
}

/**
 * 渲染 DOM 结构
 */
function render(data) {
    console.log("render")
    /*
    data = result: {
              "型号": ['A', 'B', 'C']
              "尺码": ['大', '中', '小']
              "颜色": ['红', '白', '蓝']
            }
    */
    var output = ''
    for (var i = 0; i < keys.length; i++) { //  keys = ["型号", "尺码", "颜色"]
        var key = keys[i]; // key = 型号
        var items = data[key] //  items = ["A", "B", "C"]

        output += '<dl data-type="'+ key +'" data-idx="'+ i +'">'
        output += '<dt>'+ key +':</dt>'
        output += '<dd>'
        for (var j = 0; j < items.length; j++) {
            var item = items[j]  // item = "A"
            var cName = j == 0 ? 'active' : ''  //  渲染时,每个属性中的第一个元素的className赋值为acitve
            if (j == 0) { selectedCache.push(item) }  // 每个属性的第一个元素既然已经默认选中,就保存这个选项
            output += '<button data-title="'+ item +'" class="'+ cName +'" value="'+ item +'">'+ item +'</button> '
        }
        output += '</dd>'
        output += '</dl>'
    }
    output += '</dl>'
    /*
    output = 
        "<dl data-type="颜色" data-idx="0">
            <dt>颜色:</dt>
            <dd>
                <button data-title="红" class="active" value="红">红</button>
                <button data-title="白" class="" value="白">白</button>
                <button data-title="蓝" class="" value="蓝">蓝</button>
            </dd>
        </dl>
        <dl data-type="尺码" data-idx="1">
            <dt>尺码:</dt>
            <dd>
                <button data-title="大" class="active" value="大">大</button>
                <button data-title="中" class="" value="中">中</button>
                <button data-title="小" class="" value="小">小</button>
            </dd>
        </dl>
        <dl data-type="型号" data-idx="2">
            <dt>型号:</dt>
            <dd>
                <button data-title="A" class="active" value="A">A</button>
                <button data-title="B" class="" value="B">B</button>
                <button data-title="C" class="" value="C">C</button>
            </dd>
        </dl>"
    */

    $('#app').html(output)
}

function getAllKeys(arr) {
    console.log("getAllKeys")
    /*
    arr: [{path: '红⊙大⊙A', sku: '3158055'},
            {path: '白⊙大⊙A', sku: '3158054'},
            {path: '白⊙中⊙B', sku: '3133859'},
            {path: '蓝⊙小⊙C', sku: '3516833'}]
    */
    var result = []
    /*
    result = ['红⊙大⊙A', '白⊙大⊙A', '白⊙中⊙B', '蓝⊙小⊙C']
    */
    for (var i = 0; i < arr.length; i++) { result.push(arr[i].path) }
    return result
}

/**
 * 取得集合的所有子集「幂集」
 arr = [1,2,3]

     i = 0, ps = [[]]:
         j = 0; j < ps.length => j < 1:
             i=0, j=0 ps.push(ps[0].concat(arr[0])) => ps.push([].concat(1)) => [1]
                      ps = [[], [1]]

     i = 1, ps = [[], [1]] :
         j = 0; j < ps.length => j < 2
             i=1, j=0 ps.push(ps[0].concat(arr[1])) => ps.push([].concat(2))  => [2]
             i=1, j=1 ps.push(ps[1].concat(arr[1])) => ps.push([1].concat(2)) => [1,2]
                      ps = [[], [1], [2], [1,2]]

     i = 2, ps = [[], [1], [2], [1,2]]
         j = 0; j < ps.length => j < 4
             i=2, j=0 ps.push(ps[0].concat(arr[2])) => ps.push([3])    => [3]
             i=2, j=1 ps.push(ps[1].concat(arr[2])) => ps.push([1, 3]) => [1, 3]
             i=2, j=2 ps.push(ps[2].concat(arr[2])) => ps.push([2, 3]) => [2, 3]
             i=2, j=3 ps.push(ps[3].concat(arr[2])) => ps.push([2, 3]) => [1, 2, 3]
                      ps = [[], [1], [2], [1,2], [3], [1, 3], [2, 3], [1, 2, 3]]
 */
function powerset(arr) {
    /* 
    arr = ["红", "大", "A"]
    */
    console.log("powerset")
    var ps = [[]];  // 空集是任何集合的子集,所以先推入1个空集再执行下一步
    /*
    ps = [
        [],["红"],["大"],["红","大"],["A"],["红","A"],["大","A"],["红","大","A"]
    ]
    */
    for (var i=0; i < arr.length; i++) {
        for (var j = 0, len = ps.length; j < len; j++) {
            ps.push(ps[j].concat(arr[i]));
        }
    }
    return ps;
}
/**
 * 生成所有子集是否可选、库存状态 map
 */
function buildResult(items) {
    console.log("buildResult")
    /*
    items: [{path: '红⊙大⊙A', sku: '3158055'},
            {path: '白⊙大⊙A', sku: '3158054'},
            {path: '白⊙中⊙B', sku: '3133859'},
            {path: '蓝⊙小⊙C', sku: '3516833'}]
    */
    var allKeys = getAllKeys(items)
    /*
    allKeys = ['红⊙大⊙A', '白⊙大⊙A', '白⊙中⊙B', '蓝⊙小⊙C']
    */

    for (var i = 0; i < allKeys.length; i++) {
        var curr = allKeys[i]  // curr = "红⊙大⊙A"
        var sku = items[i].sku  // sku = "3158055"
        var values = curr.split(spliter)  // values = ['红', '大', 'A']

        // allSets,不为空的集合,以求幂集的方式,获取集合的所有子集。
        var allSets = powerset(values)
        /*
        allSets = [
            [],["红"],["大"],["红","大"],["A"],["红","A"],["大","A"],["红","大","A"]
        ]
        */

        // 每个组合的子集
        for (var j = 0; j < allSets.length; j++) {
            var set = allSets[j]  // set = ["红"]
            var key = set.join(spliter)  // key = "红"

            if (res[key]) {
                res[key].skus.push(sku)
            } else {
                res[key] = {
                    skus: [sku]
                }
            }
        }
    }
}

function trimSpliter(str, spliter) {
    console.log("trimSpliter")
    /*
    页面首次加载,这个方法第一次被调用时时,str = "白⊙大⊙A", spliter = "⊙"
    */
    // ⊙abc⊙ => abc
    // ⊙a⊙⊙b⊙c⊙ => a⊙b⊙c
    var reLeft        = new RegExp('^' + spliter + '+', 'g');
    var reRight       = new RegExp(spliter + '+$', 'g');
    var reSpliter = new RegExp(spliter + '+', 'g');
    // 他这么写是为了确保万无一失,确保你传进来的路劲前面多了⊙,或者后面多了⊙,或者中间多了⊙。他都能把你的路劲改成正确的路径a⊙b⊙c
    return str.replace(reLeft, '')
        .replace(reRight, '')
        .replace(reSpliter, spliter)
}

/**
 * 获取当前选中的属性
 */
function getSelectedItem() {
    console.log("getSelectedItem")
    var result = []
    /*
    页面首次渲染时,因为我们之前创建sku每个属性时,默认是选择每个属性(颜色)里的第一个选项(红)的。
    所以,页面首次渲染时,result = ['红', '大', 'A']
    */
    $('dl[data-type]').each(function () {
        var $selected = $(this).find('.active')
        if ($selected.length) {
            result.push($selected.val())
        } else {
            result.push('')
        }
    })

    return result
}

/**
 * 更新所有属性状态
 */
function updateStatus(selected) {
    console.log("updateStatus")
    /*
    页面首次渲染时,因为我们之前创建sku每个属性时,默认是选择每个属性(颜色)里的第一个选项(红)的。
    所以,页面首次渲染时,selected = ['红', '大', 'A']
    */
   /*
   keys = ["型号", "尺码", "颜色"]
   r = {
        items: [{path: '红⊙大⊙A', sku: '3158055'},
            {path: '白⊙大⊙A', sku: '3158054'},
            {path: '白⊙中⊙B', sku: '3133859'},
            {path: '蓝⊙小⊙C', sku: '3516833'}]
        result: {
            "颜色": ['红', '白', '蓝']
            "尺码": ['大', '中', '小']
            "型号": ['A', 'B', 'C']
            }
        }
    key = 颜色
    data = ['红', '白', '蓝']
    hasActive = !!"红" ==> !false ==> true
    copy = ['红', '大', 'A']
   */
    for (var i = 0; i < keys.length; i++) {
        var key = keys[i];
        var data = r.result[key]
        var hasActive = !!selected[i]
        var copy = selected.slice()

        for (var j = 0; j < data.length; j++) {
            var item = data[j]  // item = "红"
            // 若当前项为选中项,则不执行下边的操作,跳过这次循环
            if (selected[i] == item) continue
            copy[i] = item // 因页面首次加载默认选红,所以此时item = "白", copy = ["白", "大", "A"]

            // copy.join(spliter)就已经生成正确路劲了,但是为了确保万无一失,还是用trimSpliter再次生成正确路径
            var curr = trimSpliter(copy.join(spliter), spliter)
            // curr = "白⊙大⊙A"

            // $item为"白"的所有button元素的类数组集合。<button data-title="白" class="" value="白">白</button>
            var $item = $('dl').filter('[data-type="'+ key +'"]').find('[value="'+ item +'"]')

            var titleStr = '['+ copy.join('-') +']'
            // titleStr = "[白-大-A]"

            if (res[curr]) {  // res看71行注释,curr = curr = "白⊙大⊙A",res中刚好有"白⊙大⊙A"属性。"白⊙大⊙A": { "skus": ["3158054"] }
                $item.removeClass('disabled')  // 如果res中存在curr属性,按钮就不禁用了。
                setTitle($item.get(0))
                // get() 方法获得选择器指定的 第 index(0) DOM 元素。就是$item[0],因为$("")返回的是类数组对象
            } else {
                $item.addClass('disabled').attr('title', titleStr + ' 无此属性搭配')
            }
        }
    }
}

/**
 * 正常属性点击
 */
function handleNormalClick($this) {
    console.log("handleNormalClick")
    $this.siblings().removeClass('active')
    $this.addClass('active')
}

/**
 * 无效属性点击
 */
function handleDisableClick($this) {
    console.log("handleDisableClick")
    var $currAttr = $this.parents('dl').eq(0)
    var idx = $currAttr.data('idx')
    var type = $currAttr.data('type')
    var value = $this.val()

    $this.removeClass('disabled')
    selectedCache[idx] = value

    console.log(selectedCache)
    // 清空高亮行的已选属性状态(因为更新的时候默认会跳过已选状态)
    $('dl').not($currAttr).find('button').removeClass('active')
    updateStatus(getSelectedItem())
    
    /**
     * 恢复原来已选属性
     * 遍历所有非当前属性行
     *   1. 与 selectedCache 对比
     *   2. 如果要恢复的属性存在(非 disable)且 和当前*未高亮行*已选择属性的*可组合*),高亮原来已选择的属性且更新
     *   3. 否则什么也不做
     */
    for (var i = 0; i < keys.length; i++) {
        var item = keys[i]
        var $curr = $('dl[data-type="'+ item +'"]')
        if (item == type) continue

        var $lastSelected = $curr.find('button[value="'+ selectedCache[i] +'"]')

        // 缓存的已选属性没有 disabled (可以被选择)
        if (!$lastSelected.hasClass('disabled')) {
            $lastSelected.addClass('active')
          	updateStatus(getSelectedItem())
        }
    }

}

/**
 * 高亮当前属性区
 */
function highLighAttr() {
    console.log("highLighAttr")
    for (var i = 0; i < keys.length; i++) {
        var key = keys[i]
        var $curr = $('dl[data-type="'+ key +'"]')
        if ($curr.find('.active').length < 1) {
            $curr.addClass('hl')
        } else {
            $curr.removeClass('hl')
        }
    }
}

// 最后一步了,给所有button绑定事件
function bindEvent() {
    console.log("bindEvent")
    $('#app').undelegate().delegate('button', 'click', function (e) {
        var $this = $(this)

        var isActive = $this.hasClass('.active')
        var isDisable = $this.hasClass('disabled')

        if (!isActive) {  // 如果当前按钮不是选中的按钮,则绑定一个点击事件
            handleNormalClick($this)

            if (isDisable) {  // 如果当前按钮禁用了(红-小路劲不存在时,或者C这种型号根本不存在时),绑定禁止点击的事件
                handleDisableClick($this)
            } else {  // 按钮既然绑定了点击事件,并且可以点击,在点击按钮时,把按钮的value值(红/大/A)保存在dl标签的idx属性中
                selectedCache[$this.parents('dl').eq(0).data('idx')] = $this.val()
            }
            // 这里就是更新一下各个按钮的当前的状态(按钮此时是否可以点击)高亮没选中的属性行,并刷新一下结果
            updateStatus(getSelectedItem())
            highLighAttr()
            showResult()
        }
    })

    $('button').each(function () {
        var value = $(this).val()

        if (!res[value] && !$(this).hasClass('active')) {
            $(this).addClass('disabled')
        }
    })
}

// 当所有属性项都有选时,展示用户选中的路劲,与该路劲对应的sku编号
function showResult() {
    console.log("showResult")
    // 获取当前选中的属性
    var result = getSelectedItem()
    // 页面首次加载时,则获取默认选中。result = ['红', '大', 'A']
    var s = []
    // s = ['红', '大', 'A']

    for (var i = 0; i < result.length; i++) {
        var item = result[i];
        if (!!item) {  // 将有选中的属性对应的项(红),推进去。如果item = "",则不推进去
            s.push(item)
        }
    }

    if (s.length == keys.length) {  // 如果每个属性项都有选,则获取该路径对应的sku
        var curr = res[s.join(spliter)]  // s.join(spliter) = "红⊙大⊙A",curr = { skus: ['3158055'] }

        if (curr) {  // 如果当前选中路劲存在,curr对象不为空,则将skus保存到s里面
            s = s.concat(curr.skus)  // s = ['红', '大', 'A', '3158055']
        }
        $('#msg').html('已选择:' + s.join('\u3000-\u3000'))  // \u3000就是空格
    }
}

function updateData() {
    console.log("updateData")
    data = JSON.parse($('#data_area').val())
    init(data)
}

function setTitle(el) {
    // 页面首次加载时,方法首次被调用时的情况。
    // el是文本为"白"的button元素。<button data-title="白" class="" value="白">白</button>
    console.log("setTitle")
    var title = $(el).data('title');  // title = "白"
    if (title) $(el).attr('title', title);  // 本来就有data-title = "白",现在多了个title属性,title = "白"
    // 用这个多出来的title属性,在鼠标移动到按钮顶部时,这个白按钮会提示“白”,或者“[白-大-A]无此属性搭配”,“[白-A]无此属性搭配”。
}
function setAllTitle() {
    console.log("setAllTitle")
    // 页面渲染,首次执行此函数时,app为空元素,直接跳过这里了
    $('#app').find('button').each(setTitle)
}

function init(data) {
    console.log("init")
    res = {}
    r = {}
    keys = []  // sku中的各个属性。keys = ["型号", "尺码", "颜色"]
    selectedCache = []

    for (var attr_key in data[0]) {
        if (!data[0].hasOwnProperty(attr_key)) continue;
        if (attr_key != 'skuId') keys.push(attr_key)
    }
    setAllTitle();

    r = combineAttr(data, keys)
    /*
    r = {
        items: [{path: '红⊙大⊙A', sku: '3158055'},
            {path: '白⊙大⊙A', sku: '3158054'},
            {path: '白⊙中⊙B', sku: '3133859'},
            {path: '蓝⊙小⊙C', sku: '3516833'}]
        result: {
            "型号": ['A', 'B', 'C']
            "尺码": ['大', '中', '小']
            "颜色": ['红', '白', '蓝']
            }
        }
    */

    // 在页面初次渲染时,通过keys与r.result渲染各种button等DOM元素
    render(r.result)

    // 生成一个对象,该对象的属性为幂集求来的,所有sku(r.items[0])最大路径(r.items[0].path)的子集(所有子路劲红 || 大 || A),每个属性都是一个对象,对象里有sku属性,该属性是个数组,存放包含了改子路径的最大路径(r.items[0].path)对应的sku值(r.items[0].sku)。
    buildResult(r.items)
    /*
    res = {
        "": { "skus": ["3158055","3158054","3133859","3516833"] },
        "红": { "skus": ["3158055"] },
        "大": { "skus": ["3158055","3158054"] },
        "红⊙大": { "skus": ["3158055"] },
        "A": { "skus": ["3158055","3158054"] },
        "红⊙A": { "skus": ["3158055"] },
        "大⊙A": { "skus": ["3158055","3158054"] },
        "红⊙大⊙A": { "skus": ["3158055"] },
        "白": { "skus": ["3158054","3133859"] },
        "白⊙大": { "skus": ["3158054"] },
        "白⊙A": { "skus": ["3158054"] },
        "白⊙大⊙A": { "skus": ["3158054"] },
        "中": { "skus": ["3133859"] },
        "白⊙中": { "skus": ["3133859"] },
        "B": { "skus": ["3133859"] },
        "白⊙B": { "skus": ["3133859"] },
        "中⊙B": { "skus": ["3133859"] },
        "白⊙中⊙B": { "skus": ["3133859"] },
        "蓝": { "skus": ["3516833"] },
        "小": { "skus": ["3516833"] },
        "蓝⊙小": { "skus": ["3516833"] },
        "C": { "skus": ["3516833"] },
        "蓝⊙C": { "skus": ["3516833"] },
        "小⊙C": { "skus": ["3516833"] },
        "蓝⊙小⊙C": { "skus": ["3516833"] }
    }
    */

     /*
    页面首次渲染时,因为我们之前创建sku每个属性时,默认是选择每个属性(颜色)里的第一个选项(红)的。
    所以,页面首次渲染时,getSelectedItem() = ['红', '大', 'A']
    */
    updateStatus(getSelectedItem())

    // 当所有属性项都有选时,展示用户选中的路劲,与该路劲对应的sku编号
    showResult()

    // 最后一步了,给所有button绑定事件
    bindEvent()
}

init(data)


</script>

</body>
</html>

这个是用求幂集的方式实现的sku算法,即实现了需求,又提高了性能。
sku算法的实现思路请参考
文件中的很多注释都是我自己在Chrome调试后加上去的,只是为了便于理解。不喜欢的也可以自己删掉,下面是效果。
在这里插入图片描述
这片文章我暂时就不公开了,毕竟这个需求可能比较偏,纯粹当做兴趣了解一下而已。如果大家觉得好的话,再公开吧。卑微小白博主,在线求点赞,谢谢啦!

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个React组件的代码实现,用于实现前端SKU算法商品多规格选择功能: ```jsx import React, { useState, useEffect } from "react"; const SKUSelector = ({ skuList }) => { const [selectedValues, setSelectedValues] = useState({}); const [availableOptions, setAvailableOptions] = useState({}); useEffect(() => { // 初始化可选项列表 let options = {}; skuList.forEach((sku) => { sku.attributes.forEach((attr) => { if (!options[attr.name]) { options[attr.name] = [attr.value]; } else if (!options[attr.name].includes(attr.value)) { options[attr.name].push(attr.value); } }); }); setAvailableOptions(options); }, [skuList]); const handleValueChange = (name, value) => { // 更新已选项列表 setSelectedValues({ ...selectedValues, [name]: value }); // 根据已选项列表筛选可选项列表 let options = { ...availableOptions }; for (let attrName in selectedValues) { if (attrName !== name) { skuList.forEach((sku) => { if ( sku.attributes.find((attr) => attr.name === attrName)?.value !== selectedValues[attrName] ) { options[attrName] = options[attrName].filter( (option) => option !== selectedValues[attrName] ); } }); } } setAvailableOptions(options); }; const getAvailableValues = (name) => { // 获取指定规格属性的可选项列表 return availableOptions[name] || []; }; const getSelectedSKU = () => { // 根据已选项列表获取SKU信息 let selectedSKU = null; skuList.forEach((sku) => { let matches = true; sku.attributes.forEach((attr) => { if (selectedValues[attr.name] !== attr.value) { matches = false; } }); if (matches) { selectedSKU = sku; } }); return selectedSKU; }; return ( <div> {skuList.length > 0 ? ( skuList[0].attributes.map((attr) => ( <div key={attr.name}> <label>{attr.name}:</label> <select value={selectedValues[attr.name] || ""} onChange={(e) => handleValueChange(attr.name, e.target.value)} > <option value="">请选择</option> {getAvailableValues(attr.name).map((option) => ( <option key={option} value={option}> {option} </option> ))} </select> </div> )) ) : ( <div>暂无商品信息</div> )} {getSelectedSKU() ? ( <div> <p>已选规格:{JSON.stringify(selectedValues)}</p> <p>剩余库存:{getSelectedSKU().stock}</p> </div> ) : ( <div>请选择完整规格属性</div> )} </div> ); }; export default SKUSelector; ``` 该组件接受一个SKU列表作为props,每个SKU包含一个属性列表和一个库存数量。在组件中,首先使用useEffect钩子初始化可选项列表,然后使用useState钩子管理已选项列表和可选项列表的状态。 当用户选择某个规格属性值时,组件会根据已选项列表筛选可选项列表,并更新已选项列表。当用户选择所有规格属性值后,组件会根据已选项列表获取相应的SKU信息,并显示剩余库存量。 该组件仅为示例代码,具体实现方式可能因业务需求而异。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值