规格效果图:
在这里插入图片描述

实现思路:设置商品规格
填写商品规格后,会得到规格名 privateSpecName 和规格值 dynamicTags。如:

this.privateGoodsItem = [
  {
    privateSpecName:'颜色',
    dynamicTags:['红','蓝']
  },
  { 
    privateSpecName:'尺寸',
    dynamicTags:['12']
  },
  { 
    privateSpecName:'面料',
    dynamicTags:['pvc','pe']
  }
]

处理上面的数据为:规格名为属性名,规格值为属性值。

obj= {
  '颜色':['红','蓝'],  
  '尺寸':['12'],
  '面料':['pvc','pe']
}

将上面的数据转化为:

attrName = ['颜色','尺寸','面料']
attrValue = [
  ['红','蓝'],
  ['12'],
  ['pvc','pe']
]

处理上面的数据,规格值用笛卡尔积运算改变为数组 finalArr

let attrName = ['颜色', '尺寸', '面料']
let finalArr = [
  ['红', '12', 'pvc'],
  ['红', '12', 'pe'],
  ['蓝', '12', 'pvc'],
  ['蓝', '12', 'pe']
]

处理上面的数据,将规格名规格值对应起来,变成下面的数组,用于表格内容展示

tableBodyList = [
  { '颜色':'红','尺寸':'12','面料':'pvc' },
  { '颜色':'红','尺寸':'12','面料':'pe' },
  { '颜色':'蓝','尺寸':'12','面料':'pvc' },
  { '颜色':'蓝','尺寸':'12','面料':'pe' }
]

处理规格名为表头,用于展示。

实例代码

<!DOCTYPE html>
<html lang="zh-CN" ng-strict-di>
  <meta charset="utf-8" />
  <meta name="renderer" content="webkit" />
  <meta http-equiv="Cache-Control" content="no-siteapp" />
  <meta name="X-Context-Path" content="" />
  <meta http-equiv="X-UA-Compatible" content="IE=edge" />

  <head>
    <title>
      商品规格sku
    </title>
    <link rel="stylesheet" href="https://unpkg.com/element-ui/lib/theme-chalk/index.css" />
  </head>
  <body>
    <style>
      .goods-spec {
        display: flex;
        justify-content: space-between;
        margin-bottom: 10px;
      }
      .goods-spec .goods-spec-add {
        margin-right: 15px;
      }

      .goods-container .button-new-tag {
        height: 32px;
        line-height: 30px;
        padding-top: 0;
        padding-bottom: 0;
      }
      .goods-container .input-new-tag {
        width: 90px;
        margin-right: 10px;
        vertical-align: bottom;
      }
      .goods-container .el-tag {
        margin-right: 10px;
      }
      .goods-container .goods-content {
        margin-bottom: 10px;
        padding: 14px;
        border: 1px solid #ebeef5;
        border-radius: 4px;
        background-color: #fcfcfc;
      }
      .goods-content .goods-content-box {
        display: flex;
        align-items: center;
      }
      .goods-content-box .goods-content-left {
        flex: 1;
      }
    </style>

    <div id="app">
      <div style="padding:60px;">
        <div class="goods-spec">
          <span>商品规格</span>
          <el-link type="primary" @click="addPrivateSpec" class="goods-spec-add">添加规格</el-link>
        </div>

        <div class="goods-container" v-for="(attr, index) in privateGoodsItem" :key="index">
          <div class="goods-content">
            <div class="goods-content-box">
              <div class="goods-content-left">
                <el-form label-width="80px" style="width:400px">
                  <el-form-item label="规格名">
                    <el-input v-model="attr.privateSpecName" placeholder="请输入规格名"></el-input>
                  </el-form-item>
                  <el-form-item label="规格值">
                    <el-tag v-for="tag in attr.dynamicTags" :key="tag" closable :disable-transitions="false" @close="handleClose(tag, attr)">
                      {{ tag }}
                    </el-tag>
                    <el-input
                      class="input-new-tag"
                      v-if="attr.inputVisible"
                      v-model="attr.inputValue"
                      :ref="`saveTagInput${index}`"
                      size="small"
                      @keyup.enter.native="handleInputConfirm(attr.inputValue, attr)"
                      @blur="handleInputConfirm(attr.inputValue, attr)"
                    >
                    </el-input>
                    <el-button v-else class="button-new-tag" size="small" @click="showInput(attr, index)">+ 添加</el-button>
                  </el-form-item>
                </el-form>
              </div>
              <div class="goods-content-right">
                <el-link type="danger" @click="delPrivateSpec(index)">删除规格</el-link>
              </div>
            </div>
          </div>
        </div>

        <p style="margin:24px 0 10px 0">价格 / 库存</p>
        <el-table ref="multipleTable" :data="tableColumnList.tableBodyList" stripe tooltip-effect="dark" style="width: 100%;margin-top:1%;">
          <el-table-column :label="item.propName" :property="item.prop" v-for="item in tableColumnList.tableHeaderList" :key="item.prop" align="center">
            <template slot-scope="scope">
              <span>{{ scope.row[scope.column.property] }}</span>
            </template>
          </el-table-column>
          <el-table-column label="价格(元)">
            <template slot-scope="scope">
              <el-input v-model.number="scope.row.price"></el-input>
            </template>
          </el-table-column>
          <el-table-column label="库存">
            <template slot-scope="scope">
              <el-input v-model.number="scope.row.stock"></el-input>
            </template>
          </el-table-column>
          <el-table-column label="库存预警">
            <template slot-scope="scope">
              <el-input v-model.number="scope.row.low_stock"></el-input>
            </template>
          </el-table-column>
        </el-table>
      </div>
    </div>

    <!-- 先引入 Vue -->
    <script src="https://unpkg.com/vue/dist/vue.js"></script>
    <!-- 引入组件库 -->
    <script src="https://unpkg.com/element-ui/lib/index.js"></script>
    <script src="https://cdn.staticfile.org/vue-resource/1.5.1/vue-resource.min.js"></script>

    <script>
      var app = new Vue({
        el: '#app',
        data: {
          tableColumnList: {
            tableHeaderList: [],
            tableBodyList: []
            // inventory: ''
          },
          privateGoodsItem: [
            {
              privateSpecName: '', //规格名
              dynamicTags: [], //规格值数组
              inputVisible: false,
              inputValue: ''
            }
          ]
        },
        computed: {
          // 计算规格
          calculateAttribute() {
            // 初始化
            let obj = {}
            this.privateGoodsItem.forEach((item) => {
              // 判断有没有输入规格名
              if (item.privateSpecName) {
                //规格名:规格值     //'颜色':'尺寸'
                obj[item.privateSpecName] = item.dynamicTags
              }
            })
            return obj
          }
        },
        watch: {
          // 监听规格数据
          calculateAttribute(newVal) {
            let cloneNewVal = JSON.parse(JSON.stringify(newVal))
            let attrName = [] //规格名数组
            let attrValue = [] //规格值数组
            for (let key in cloneNewVal) {
              attrName.push(key)
              attrValue.push(cloneNewVal[key])
            }

            // 表格内容数据(笛卡尔积算法)
            let finalArr = this.cartesianProductOf(...attrValue)

            let tableObj = {
              tableBodyList: [],
              tableHeaderList: []
            }
            // 表格内容
            tableObj.tableBodyList = finalArr.map((item) => {
              let obj = {
                price: 0,
                stock: 0,
                low_stock: 0
              }
              for (let i = 0; i < item.length; i++) {
                obj[attrName[i]] = item[i]
              }
              return obj
            })
            this.tableColumnList.tableBodyList = tableObj.tableBodyList //表格内容数据

            // 表头
            let skuTableArr = Object.keys(newVal)
            tableObj.tableHeaderList = skuTableArr.map((item) => {
              return {
                prop: item,
                propName: item
              }
            })
            this.tableColumnList.tableHeaderList = tableObj.tableHeaderList // 表头
          }
        },
        methods: {
          // 添加规格
          addPrivateSpec(index) {
            this.privateGoodsItem.push({
              privateSpecName: '',
              dynamicTags: [],
              inputVisible: false,
              inputValue: ''
            })
          },
          delPrivateSpec(index) {
            this.privateGoodsItem.splice(index, 1)
          },
          handleInputConfirm(val, attr) {
            if (val) {
              attr.dynamicTags.push(val)
            }
            attr.inputVisible = false
            attr.inputValue = ''
          },
          handleClose(tag, item) {
            item.dynamicTags.splice(item.dynamicTags.indexOf(tag), 1)
          },
          showInput(attr, index) {
            attr.inputVisible = true
            this.$nextTick((_) => {
              this.$refs[`saveTagInput${index}`][0].$refs.input.focus()
            })
          },
          // 笛卡尔积算法
          cartesianProductOf(...args) {
            return args.reduce(
              (total, current) => {
                let ret = []
                total.forEach((a) => {
                  current.forEach((b) => {
                    ret.push(a.concat([b]))
                  })
                })
                return ret
              },
              [[]]
            )
          }
        }
      })
    </script>
  </body>
</html>
Logo

前往低代码交流专区

更多推荐