vue-sku-form
组件
https://hooray.github.io/vue-sku-form/guide/
另外一个比较简单 的
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Vue 实现商品属性的计算显示</title> <style> body { font-size: 12px; } dt { width: 100px; text-align: right; } dl { clear: both; overflow: hidden; } dt, dd { float: left; height: 40px; line-height: 40px; margin-left: 10px; } button { font-size: 14px; font-weight: bold; width: 100px; height: 30px; margin: 0 10px; } .active { color: red; background-color:#8EC6FF; } </style> </head> <body> <div id="app"> <template> {{ selectedTypeDesc }} <dl v-if="JSON.stringify(selectedResult)!='{}'"> 当前属性:{{'编号:'+selectedResult.skuId+'-库存:'+selectedResult.remain+'-价格:'+selectedResult.price}} </dl> <dl v-for="(item, key) in specTypes"> <dt> {{key}} :</dt> <dd> <button class="item" v-for="value in item" @click="handleActive(key, value)" :disabled="value.disabled" v-bind:class="{active: value.active}" > {{ value.name }} </button> </dd> </dl> </template> </div> </body> <script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script> <script> const tempData = {}; let types = [ {typeTitle: 'A', typeValues: ['大','中', '小']}, {typeTitle: 'B', typeValues: ['黄', '绿','紫','白','黑','红']}, {typeTitle: 'C', typeValues: ['重', '轻']}]; let skuList = { '大-黄-重': {skuId: 1, remain: 30, price: 99}, '小-红-轻': {skuId: 2, remain: 10, price: 56}, '大-红-重': {skuId: 3, remain: 2, price: 198} }; let vue = new Vue({ el: "#app", data() { return { specTypes: {skuId: 1, remain: 30, price: 99},//规则属性 specValues: [],//规则属性节点 skuList: {},//sku对象,后台格式化好 selectedResult: {},//选中的最终规则-展现用 selectedTypeDesc: "请选择",//选中后展示信息 selectedType: {},//选中的规则 }; }, methods: { /** * 点击按钮节点触发事件 */ handleActive: function (key, node) { node.active = !node.active; if (node.active) { this.selectedType[key] = node.name; //更新同组其他按钮状态 this.specTypes[key].forEach(x => { if (x.name != node.name) { x.active = false; } }); } else { this.selectedType[key] = ''; } this.refreshSpecTypeNodes() // console.log('this.selectedType', this.selectedType) // console.log('this.specTypes', this.specTypes) let selectedSku = this.getSelectedSku(); this.selectedTypeDesc = selectedSku.desc; this.selectedResult = selectedSku.sku; }, /** * 获取当前选择的规则信息 */ getSelectedSku: function () { let m = "请选择", selected = [], sku = {}, keys = [], values = []; keys = Object.keys(this.selectedType); keys.forEach(x => { if (!Object.is(this.selectedType[x], null) && !Object.is(this.selectedType[x], '')) { selected.push(x + ":" + this.selectedType[x]); } }) values = Object.values(this.selectedType); if (values.length === keys.length) { let key = values.join('-'); if (this.skuList.hasOwnProperty(key)) { sku = this.skuList[key]; } } if (selected.length > 0) { m = "已选择:"; m += selected.join(";"); } return { desc: m, sku: sku }; }, /*** * 刷新规则属性状态 */ refreshSpecTypeNodes() { let types = this.specTypes, currentSelected = this.selectedType; Object.keys(types).forEach(x => { let nodes = types[x]; for (let i = 0; i < nodes.length; i++) { let node = nodes[i], tempSelected = {}; tempSelected[x] = node.name; let selected = Object.values(Object.assign({}, currentSelected, tempSelected)); let s = this.getRemainByKey(selected.filter(x => x)); if (s > 0) { node.disabled = false; } else { node.disabled = true; node.active = false; } } }) }, /** * 初始化 */ init: function () { let result = this.recombineSpecTypes(types); this.specTypes = result; this.skuList = skuList; this.selectedType = this.initSelectedType(result); this.selectedTypeDesc = this.getSelectedSku().desc; this.refreshSpecTypeNodes() console.log('this.specTypes', this.specTypes) }, /** * 初始化已选规则 */ initSelectedType: function (types) { let selectedType = {}; let keys = Object.keys(types); keys.forEach(x => { selectedType[x] = ''; }) return selectedType; }, /** * 重构规则结构 * */ recombineSpecTypes: function (types) { let result = {}; let specValues = []; for (let i = 0; i < types.length; i++) { let item = types[i]; specValues.push(item.typeValues); let values = []; for (let j = 0; j < item.typeValues.length; j++) { let value = item.typeValues[j]; values.push({ 'active': false, 'name': value, 'disabled': false }); } result[item.typeTitle] = values } this.specValues = specValues; return result; }, /** * 获取所选值对应的库存 * @param selected 数组['大','黄'] * @returns {number|*} */ getRemainByKey: function (selected) { const key = selected.join('-') if (typeof tempData[key] !== 'undefined') { return tempData[key] } if (selected.length === this.specValues.length) { return this.skuList[key] ? tempData[key] = this.skuList[key].remain : tempData[key] = 0 } let remain = 0 let tempSelected = [] for (let i = 0; i < this.specValues.length; i++) { const exist = this.specValues[i].find(_item => _item === selected[0]) if (exist && selected.length > 0) { tempSelected.push(selected.shift()) } else { this.specValues[i].forEach(_item => { remain += this.getRemainByKey(tempSelected.concat(_item, selected)) }) break } } return tempData[key] = remain }, }, created() { this.init(); } }) </script> </html>