element根据输入动态生成表格的示例代码
作者:vvvbird
在现代电商系统开发中,后台管理界面经常需要根据商品规格和规格值动态生成SKU表格,本文通过element-ui框架,展示了如何在Vue.js的环境下,利用子组件和动态绑定的方式,实现SKU表格的增删改查功能
场景:后台页面根据商品规格和规格值,动态(增删改查)在表格中生成对应的sku. 如图:
代码如下:
edit.html
<template xmlns=""> <div class="app-container"> <el-form ref="form" :model="form" label-width="80px" autocomplete="off" @submit.native.prevent> <h3>基础信息</h3> <div style="padding-left: 60px"> <el-row> <el-col :span="7"> <el-form-item label="spu_id"> <el-input v-model="form.id" autocomplete="off" placeholder="" :disabled="true" /> </el-form-item> </el-col> <el-col :span="5"> <el-form-item label="名称" :required="true"> <el-input v-model="form.goods_name" autocomplete="off" placeholder="" /> </el-form-item> </el-col> <el-col :span="5"> <el-form-item label="商品类型" :required="true"> <el-select v-model="form.goods_type" placeholder="请选择"> <el-option v-for="item in goodsTypeOptions" :key="item.value" :label="item.label" :value="item.value"> </el-option> </el-select> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="5"> <el-form-item label="品牌" :required="true"> <el-select v-model="form.brand_code" style="width: 100%"> <el-option v-for="item in brandOptions" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> </el-col> <el-col :span="5"> <el-form-item label="分类" :required="true"> <el-cascader v-model="form.cate_code" collapse-tags clearable :options="cateOptions" :props="{ multiple: false, checkStrictly: true }" filterable style="width: 100%" /> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="5"> <el-form-item label="赠品" :required="true"> <el-radio v-model="form.is_gift" label="1">否</el-radio> <el-radio v-model="form.is_gift" label="2">是</el-radio> </el-form-item> </el-col> <el-col :span="5"> <el-form-item label="列表显示" :required="true"> <el-radio v-model="form.is_show_video" label="1">是</el-radio> <el-radio v-model="form.is_show_video" label="2">否</el-radio> </el-form-item> </el-col> <el-col :span="5"> <el-form-item label="是否套组" :required="true"> <el-radio v-model="form.is_suite" label="1">否</el-radio> <el-radio v-model="form.is_suite" label="2">是</el-radio> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="5"> <el-form-item label="是否预售" :required="true"> <el-radio v-model="form.is_pre_sales" label="1">否</el-radio> <el-radio v-model="form.is_pre_sales" label="2">是</el-radio> </el-form-item> </el-col> <el-col :span="5"> <el-form-item label="是否临期" :required="true"> <el-radio v-model="form.is_expire" label="1">否</el-radio> <el-radio v-model="form.is_expire" label="2">是</el-radio> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="5"> <el-form-item label="包装规格"> <el-input v-model="form.pack_spec" autocomplete="off" placeholder="" /> </el-form-item> </el-col> <el-col :span="5"> <el-form-item label="包装数量"> <el-input v-model="form.pack_count" autocomplete="off" placeholder="" /> </el-form-item> </el-col> <el-col :span="5"> <el-form-item label="销售单位"> <el-input v-model="form.unit_name" autocomplete="off" placeholder="" /> </el-form-item> </el-col> <el-col :span="5"> <el-form-item label="保质期"> <el-date-picker v-model="form.expire_date" type="date" value-format="yyyy-MM-dd" placeholder="选择日期" /> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="24"> <el-form-item label="商品图片" :required="true"> <ul class="el-upload-list el-upload-list--picture-card"> <vuedraggable v-model="form.images"> <li v-for="(item, index) in form.images" :key="index" class="el-upload-list__item is-success animated"> <img :src="item" alt="" class="el-upload-list__item-thumbnail "> <i class="el-icon-close" /> <span class="el-upload-list__item-actions"> <!-- 预览 --> <span class="el-upload-list__item-preview" @click="viewImage(item)"> <i class="el-icon-zoom-in" /> </span> <!-- 删除 --> <span class="el-upload-list__item-delete" @click="delImage(index)"> <i class="el-icon-delete" /> </span> </span> </li> </vuedraggable> </ul> <!-- <el-button size="small" type="info" @click="uploadImageDialog = true">点击上传</el-button>--> <label for="upload-btn" class="el-button el-button--info el-button--mini">上传文件</label> <input v-show="false" id="upload-btn" ref="uploadBtn" type="file" accept="image/png, image/jpeg, image/gif, image/jpg" @change="loadImg($event)" > <div class="el-upload__tip">第1张为主图,其它为从图.尺寸800*800</div> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="7"> <el-form-item label="推荐语"> <el-input v-model="form.recommendation" autocomplete="off" placeholder="" /> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="24"> <el-form-item label="描述" :required="true"> <tinymce v-model="form.description" :height="300" /> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="12"> <el-form-item label="保管事项"> <el-select v-model="form.keep_desc_tpl_id" placeholder="请选择" style="width: 100%"> <el-option v-for="item in keepOptions" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="温馨提示"> <el-select v-model="form.notice_desc_tpl_id" placeholder="请选择" style="width: 100%"> <el-option v-for="item in noticeOptions" :key="item.value" :label="item.label" :value="item.value" /> </el-select> </el-form-item> </el-col> </el-row> </div> <h3>sku信息</h3> <div style="padding-left: 60px"> <sku-edit ref="skuEdit" /> </div> <el-form-item> <el-button type="primary" @click="save">保存</el-button> <router-link style="padding-left: 10px;" to="/goods/erp-goods-list"> <el-button>返回列表</el-button> </router-link> </el-form-item> </el-form> <el-dialog :visible.sync="imageViewDialog"> <img width="100%" :src="imageViewUrl" alt=""> </el-dialog> <el-dialog width="700px" custom-class="image-upload" :visible.sync="croperImageDialog" :close-on-click-modal="false" @close="emptyUpload" > <div style="display:flex;justify-content: center;"> <cropper ref="myCropper" @updateImageList="updateImageList" /> </div> <div slot="footer"> <div class="dialog-footer-btn"> <div> <el-button @click="croperImageDialog = false">返 回</el-button> <el-button type="primary" @click="cropImg">确 定</el-button> </div> </div> </div> </el-dialog> </div> </template> <script> import { spuCreate, spuDetail } from '@/api/goods/goods' import { getOptions, uploadUrl } from '@/api/common/common' import { empty } from '@/utils/index' import Tinymce from '@/components/Tinymce/index.vue' import skuEdit from '@/views/goods/goods/sku_edit.vue' import { getToken } from '@/utils/auth' import vuedraggable from 'vuedraggable' import cropper from '@/views/goods/component/cropper.vue' export default { name: 'GoodsEdit', components: { Tinymce, vuedraggable, cropper, skuEdit }, props: ['id'], data() { return { salesAmountLimit: 1, uploadImageDialog: false, croperImageDialog: false, imageViewDialog: false, imageViewUrl: false, uploadUrl: uploadUrl, cropperDialogVisible: false, tagOptions: [], keepOptions: [], noticeOptions: [], uppy: {}, cateOptions: [], brandOptions: [], goodsTypeOptions: [], uploadHeaders: { token: getToken() }, leftTagFileList: [], rightTagFileList: [], form: {}, copy: false, initForm: { id: '', goods_name: '', barcode: '', cate_code: '', brand_code: '', description: '', images: [], pack_spec: '', pack_count: '', unit_name: '', expire_date: '', video: '', is_expire: '1', is_gift: '1', is_pre_sales: '1', video_cover: '', is_show_video: '1', recommendation: '', goods_type: '1', is_suite: '1', merchant_id: '', keep_desc_tpl_id: '', notice_desc_tpl_id: '', sku_map_list: [], spu_attrs: [] } } }, computed: {}, watch: { 'form.left_tag_type': { deep: true, handler(newVal, oldVal) { if ((newVal === 7 && oldVal !== 7) || (newVal !== 7 && oldVal === 7)) { this.form.left_tag = '' this.leftTagFileList = [] } } }, 'form.right_tag_type': { deep: true, handler(newVal, oldVal) { if ((newVal === 7 && oldVal !== 7) || (newVal !== 7 && oldVal === 7)) { this.form.right_tag = '' this.rightTagFileList = [] } } } }, mounted() { if (this.$route.query.copy) { this.copy = JSON.parse(this.$route.query.copy) } }, activated() { this.form = JSON.parse(JSON.stringify(this.initForm)) this.detail() getOptions({ option_names: [ 'cateOptions', 'brandOptions', 'goodsTypeOptions', 'goodsDescTplOption', 'goodsKeepTplOption'] }).then(response => { this.goodsTypeOptions = response.data.goodsTypeOptions this.cateOptions = response.data.cateOptions this.brandOptions = response.data.brandOptions this.keepOptions = response.data.goodsKeepTplOption this.noticeOptions = response.data.goodsDescTplOption }) }, methods: { async save() { // 获取 skuEdit 子组件 的信息 this.form.sku_map_list = this.$refs.skuEdit.spuInfo.sku_map_list // is_draft =1 为草稿数据 2-为审核通过的数据 this.form.is_draft = 2 await spuCreate(this.form) this.$message({ message: '保存成功,待审核!', type: 'success' }) this.form = JSON.parse(JSON.stringify(this.initForm)) this.$router.push({ path: '/goods/goods/draft-list' }) }, detail() { const id = this.$route.query.id const params = {} params.id = id if (empty(id)) { return } spuDetail(params).then(response => { this.form = response.data this.$refs.skuEdit.spuInfo.sku_map_list = this.form.sku_map_list this.$refs.skuEdit.spuAttrs = this.form.spu_attrs this.form.is_expire = this.form.is_expire.toString() this.form.is_gift = this.form.is_gift.toString() this.form.is_show_video = this.form.is_show_video.toString() this.form.is_suite = this.form.is_suite.toString() this.form.is_pre_sales = this.form.is_pre_sales.toString() this.form.is_expire = this.form.is_expire.toString() if (this.copy) { this.form.id = '' } }) }, viewImage(item) { this.imageViewUrl = item.url this.imageViewDialog = true }, delImage(index) { this.form.images.splice(index, 1) }, loadImg(e) { const file = e.target.files[0] if (file.size / 1024 / 1024 > 5) { this.$message.error('上传文件不能超过5M') return false } if (!/\.(jpg|png|gif|JPG|PNG|GIF|)$/.test(file.name)) { this.$message.info('图片类型必须是jpg,png的一种') return false } const reader = new FileReader() reader.onload = (e) => { let data if (typeof e.target.result === 'object') { data = window.URL.createObjectURL(new Blob([e.target.result])) } else { data = e.target.result } this.croperImageDialog = true this.$nextTick(() => { this.$refs.myCropper.imgLoad(file, data) }) } reader.readAsArrayBuffer(file) }, emptyUpload() { this.$refs.uploadBtn.value = '' }, cropImg() { this.$refs.myCropper.crop() }, updateImageList(item) { this.form.images.push(item.url) this.croperImageDialog = false } } } </script> <style lang="scss" scoped> .app-container { overflow-y: auto; height: 100%; } .app-container >>> .cropper-modal { opacity: 0.5; } el-input { width: 300px; } </style>
子组件sku_edit.html
<template> <div class=""> <el-form ref="SkuEdit" label-width="110px"> <el-form-item label="spu规格" required> <vuedraggable v-model="spuAttrs" @start="onStart" @end="onEnd"> <transition-group> <template v-for="(item, index) in spuAttrs"> <div :key="index" :class="(index < (spuAttrs.length - 1)) ? 'attr_select_index' : '' "> <div> <el-select v-model="item.attr" filterable allow-create placeholder="选择或创建" size="mini" @blur="addAttr($event,item,index)" @change="changeAttr($event, index)" > <el-option v-for="(cateItem, cateIndex) in cateAttrs" :key="cateIndex" :label="cateItem.label" :value="cateIndex" /> </el-select> <i :key="index" class="item el-icon-sort" @mouseover="showTooltipSpec" @mouseleave="hideTooltipSpec" /> <span v-if="tooltipVisibleSpec&&index===0">拖动上下排序</span> <i :key="index" class="el-icon-circle-plus attr_options_add" @click="spuAttrItem(1, index + 1)" /> <i v-if="spuAttrs.length>1" :key="index" class="el-icon-remove attr_options_del" @click="spuAttrItem(2,index)" /> </div> <div style="margin-left: 20px"> <vuedraggable v-model="item.values" @start="onStart" @end="onEnd"> <transition-group style="display: flex; flex-wrap: wrap;"> <template v-for="(attrVal,vi) in item.values"> <div :key="vi"> <div style="margin-left: 15px"> <el-input v-model="item.values[vi]" placeholder="添加规格值" size="mini" style="width: 100px;" @blur="addAttrValue($event,index, vi)" /> <template> <i :key="vi" class="item el-icon-s-operation" @mouseover="showTooltipSpecValue" @mouseleave="hideTooltipSpecValue" /> <span v-if="tooltipVisibleSpecValue&&vi===0&&index===0">拖动左右排序</span> <i :key="vi" class="el-icon-circle-plus attr_val_options_add" @click="spuAttrValueItem(1,index)" /> <i v-if="item.values.length>1" :key="vi" class="el-icon-remove attr_val_options_del" @click="spuAttrValueItem(2,index,vi)" /> </template> </div> </div> </template> </transition-group> </vuedraggable> </div> </div> </template> </transition-group> </vuedraggable> </el-form-item> <el-form-item label="映射sku" required> <el-table :data="spuInfo.sku_map_list" border :header-row-style="tableHeaderRowStyle" :header-cell-style="tableHeaderCellStyle" :max-height="tableHeight" size="mini" style="width: 100%" empty-text="暂无数据" > <el-table-column v-for="(item,index) in spuAttrs" :key="index" :label="item.attr" > <template slot-scope="scop"> <div>{{ getAttrValue(scop.row, index) }}</div> </template> </el-table-column> <el-table-column prop="barcode" label="商品条码" > <template slot-scope="scope"> <el-input v-model="scope.row.barcode" size="mini" placeholder="请输入商品条码" @blur="addBarcode($event,scope.row,scope.$index)" /> </template> </el-table-column> <el-table-column prop="price" label="售价" > <template slot-scope="scope"> <el-input v-model="scope.row.price" size="mini" placeholder="请输入商品售价" @blur="addPrice($event,scope.row,scope.$index)" /> </template> </el-table-column> <el-table-column prop="market_price" label="市场价" > <template slot-scope="scope"> <el-input v-model="scope.row.price" size="mini" placeholder="请输入商品市场价" @blur="addMarketPrice($event,scope.row,scope.$index)" /> </template> </el-table-column> <el-table-column prop="image" label="图片" width="100" > <template slot-scope="scope"> <el-upload class="avatar-uploader" :action="uploadUrl+'?type=image'" :limit="1" :show-file-list="false" :on-success="(res,file,fileList) => {handleAvatarSuccess(res,file,fileList,scope.$index)}" :headers="uploadHeaders" > <img v-if="scope.row.image!=''" :src="scope.row.image" class="avatar"> <i v-else class="el-icon-plus avatar-uploader-icon" /> </el-upload> </template> </el-table-column> </el-table> </el-form-item> </el-form> </div> </template> <script> import vuedraggable from 'vuedraggable' import { getOptions, uploadUrl } from '@/api/common/common' import { spuDetail, saveSpu } from '@/api/goods/spu' import { empty } from '@/utils' import Common from '@/layout/mixin/Common' import { getToken } from '@/utils/auth' export default { name: 'SkuEdit', components: { 'vuedraggable': vuedraggable }, mixins: [Common], props: ['spu_id'], data() { return { // 1-为规格 2-为规格值 changeType: 1, // 变化内容 changeContent: '', drag: false, tooltipVisibleSpec: false, tooltipVisibleSpecValue: false, uploadUrl: uploadUrl, spuInfo: { sku_map_list: [] }, uploadHeaders: { token: getToken() }, cateAttrs: [], cateAttrCount: 0, spuAttrs: [], selectMapSkuVisible: false, skuListLoading: false, skuList: [], barcode: '', goodsName: '', selectSkuPage: 1, selectSkuPageSize: 30, selectSkuTotal: 0, selectSkuMapIndex: -1 } }, mounted() { getOptions({ option_names: ['spuSpecOptions'] }).then(response => { this.cateAttrs = response.data.spuSpecOptions }) if (!empty(this.spu_id)) { this.spuInfo.id = this.spu_id spuDetail({ id: this.spu_id }).then(res => { this.cateAttrCount = Object.keys(this.cateAttrs).length this.spuInfo.sku_map_list = res.data.sku_map_list this.spuAttrs = res.data.spu_attrs this.$refs.imageCropperUpload.setImage([{ path: this.spuInfo.image, url: this.spuInfo.image_url }]) }) } if (empty(this.spuAttrs)) { this.spuAttrs = [ { attr: '', values: [''] } ] } }, methods: { empty, showTooltipSpec() { console.log('showTooltipSpec','----------') setTimeout(() => { this.tooltipVisibleSpec = true }, 1000) }, hideTooltipSpec() { console.log('hideTooltipSpec','----------') this.tooltipVisibleSpec = false }, showTooltipSpecValue() { console.log('showTooltipSpecValue','----------') setTimeout(() => { this.tooltipVisibleSpecValue = true }, 1000) }, hideTooltipSpecValue() { console.log('hideTooltipSpecValue','----------') this.tooltipVisibleSpecValue = false }, onStart() { this.drag = true }, handleAvatarSuccess(res, file, fileList, index) { this.spuInfo.sku_map_list[index].image = res.data[0].url }, // 添加规格 addAttr(e, item, index) { if (empty(e.target.value)) { return } this.spuAttrs.push({ attr: e.target.value, values: [''] }) // 判断this.spuAttrs.attr 是否有空值,如果有空值则删除 for (let i = 0; i < this.spuAttrs.length; i++) { if (empty(this.spuAttrs[i].attr)) { this.spuAttrs.splice(i, 1) } } }, addBarcode(e, row, index) { this.spuInfo.sku_map_list[index].barcode = e.target.value }, addPrice(e, row, index) { this.spuInfo.sku_map_list[index].price = e.target.value }, addMarketPrice(e, row, index) { this.spuInfo.sku_map_list[index].market_price = e.target.value }, addAttrValue(e, index, vi) { if (empty(e.target.value)) { return } this.attrSkuMap(1, index, this.spuAttrs[index].values.length - 1) }, onEnd() { this.drag = false this.attrSkuMap(3, 0, 0) }, // 选择规格名 changeAttr(e, index) { this.spuAttrs[index].values = [''] this.spuAttrs[index].attr = this.cateAttrs[index].label this.attrSkuMap(3, index, -1) }, spuAttrItem(type, index) { if (type === 1) { this.spuAttrs.push({ attr: '', values: [''] }) } else { this.changeType = 1 this.changeContent = this.spuAttrs[index].attr this.spuAttrs.splice(index, 1) } this.attrSkuMap(type, index, type === 1 ? 0 : 1) }, // 添加|删除规格值 spuAttrValueItem(type, pIndex, subIndex) { if (type === 1) { this.spuAttrs[pIndex].values.push('') } else { this.changeType = 2 this.changeContent = this.spuAttrs[pIndex].values[subIndex] this.spuAttrs[pIndex].values.splice(subIndex, 1) } this.attrSkuMap(type, pIndex, subIndex) }, // 生成sku组合表格,处理每行数据x generateCombinations(type, pIndex, subIndex, changeIndex = 0, spliceIndex = -1, currentCombination = [], index = 0) { if (index >= this.spuAttrs.length) { // 1-新增,2-删除,3-修改 if (type === 1) { // 页面新开 新增的sku情况 if (empty(this.spuInfo.sku_map_list[changeIndex])) { this.spuInfo.sku_map_list.push({ barcode: '', price: '', market_price: '', attrs: [], image: '' }) // attrs 字段与页面显示无关,只为传给后端使用 for (let j = 0; j < currentCombination.length; j++) { this.spuInfo.sku_map_list[changeIndex].attrs.push({ attr: currentCombination[j].attr, value: currentCombination[j].value }) } // 页面新开 编辑的sku情况 } else if (currentCombination.length === this.spuInfo.sku_map_list[changeIndex].attrs.length) { for (let j = 0; j < currentCombination.length; j++) { this.spuInfo.sku_map_list[changeIndex].attrs[j].attr = currentCombination[j].attr this.spuInfo.sku_map_list[changeIndex].attrs[j].value = currentCombination[j].value } } else if (currentCombination.length > this.spuInfo.sku_map_list[changeIndex].attrs.length) { const item = currentCombination.slice(-1) this.spuInfo.sku_map_list[changeIndex].attrs.push({ attr: item.attr, value: item.value }) } } else if (type === 2) { // 遍历currentCombination,把value 拼接组合,后面在循环中删除多余重复的行 if (this.changeType === 1) { let currentCombinationValue = '' for (let j = 0; j < currentCombination.length; j++) { currentCombinationValue += currentCombination[j].value + '_' } for (let k = 0; k < this.spuInfo.sku_map_list.length; k++) { if (empty(this.spuInfo.sku_map_list[k])) { continue } for (let j = 0; j < this.spuInfo.sku_map_list[k].attrs.length; j++) { if (empty(this.spuInfo.sku_map_list[k].attrs[j])) { continue } if (this.changeContent === this.spuInfo.sku_map_list[k].attrs[j].attr ) { // 删除规格 this.spuInfo.sku_map_list[k].attrs.splice(j, 1) // 组合规格值 let itemValueCombination = '' for (let m = 0; m < this.spuInfo.sku_map_list[k].attrs.length; m++) { itemValueCombination += this.spuInfo.sku_map_list[k].attrs[m].value + '_' } this.spuInfo.sku_map_list[k].combination = itemValueCombination } } } for (let v = 0; v < this.spuInfo.sku_map_list.length; v++) { let count = 0 if (empty(this.spuInfo.sku_map_list[v])) { continue } if (currentCombinationValue === this.spuInfo.sku_map_list[v].combination) { count++ } // 相同规格的行只保留一条 if (count > 1) { this.spuInfo.sku_map_list.splice(v, 1) } } } else { for (let k = 0; k < this.spuInfo.sku_map_list.length; k++) { if (empty(this.spuInfo.sku_map_list[k]) || empty(this.spuInfo.sku_map_list[k].attrs)) { continue } const attrs = this.spuInfo.sku_map_list[k]?.attrs || [] for (let j = 0; j < attrs.length; j++) { if (this.empty(attrs[j])) { continue } if (this.changeContent === attrs[j].value) { // 删除整行 this.spuInfo.sku_map_list.splice(k, 1) break // 如果删除了当前行,需要跳出循环 } } } } } else { for (let j = 0; j < currentCombination.length; j++) { this.spuInfo.sku_map_list[changeIndex].attrs[j].attr = currentCombination[j].attr this.spuInfo.sku_map_list[changeIndex].attrs[j].value = currentCombination[j].value } } changeIndex++ spliceIndex = -1 // return 之后执行 this.generateCombinations 的逻辑 return [changeIndex, spliceIndex] } // 规格和规格值都遍历 for (var i = 0; i < this.spuAttrs[index].values.length; i++) { currentCombination.push({ attr: this.spuAttrs[index].attr, value: this.spuAttrs[index].values[i] }) // 假如有 尺寸 S M ,颜色 黄色 白色 // 第一次遍历生成 {"attr":"尺寸","value":"S"} // 第二次遍历生成 {"attr":"尺寸","value":"S"},{"attr":"颜色","value":"黄色"}组合,然后在渲染到表格的第一行中 // changeIndex 为行数或者组合数量 // generateCombinations 自循环,遇到return [changeIndex, spliceIndex]后才往下执行 const res = this.generateCombinations(type, pIndex, subIndex, changeIndex, spliceIndex, currentCombination, index + 1) changeIndex = res[0] spliceIndex = res[1] currentCombination.pop() } return [changeIndex, spliceIndex] }, attrSkuMap(type, pIndex, subIndex) { this.generateCombinations(type, pIndex, subIndex) return }, getAttrValue(item, i) { return item.attrs[i].value }, async saveSpu() { return await saveSpu(this.spuInfo) } } } </script> <style scoped lang="scss"> .cate_level1 { color: #E6A23C; } .attr_select_index { margin-bottom: 14px; } .attr_options_add, .attr_val_options_add { margin-left: -2px; font-size: 20px; color: #409EFF; cursor: pointer; } .item { padding: 3px; //background-color: #fdfdfd; //border: solid 1px #eee; margin-bottom: 10px; cursor: move; } .item:hover { background-color: #f1f1f1; cursor: move; } .chosen { border: solid 2px #3089dc !important; } .attr_options_del, .attr_val_options_del { margin-left: -2px; font-size: 20px; color: #F56C6C; cursor: pointer; } .tooltip-container { position: relative; display: inline-block; } .tooltip-text { visibility: visible; width: 120px; background-color: black; color: #fff; text-align: center; border-radius: 6px; padding: 5px 0; position: absolute; z-index: 1; bottom: 125%; /* Position the tooltip above the icon */ left: 50%; margin-left: -60px; opacity: 0; transition: opacity 0.3s; } .tooltip-container:hover .tooltip-text { visibility: visible; opacity: 1; } .avatar-uploader .el-upload { border: 1px dashed #d9d9d9; border-radius: 6px; cursor: pointer; position: relative; overflow: hidden; } .avatar-uploader .el-upload:hover { border-color: #409EFF; } .avatar-uploader-icon { font-size: 28px; color: #8c939d; width: 30px; height: 30px; line-height: 30px; text-align: center; } .avatar { width: 30px; height: 30px; display: block; } </style>
数据结构
{ "msg": "ok", "code": 10000, "data": { "id": "710432902999261184", "goods_name": "spu测试ywz", "cate_code": "Lthg98", "brand_code": "UpsPhd", "supplier_code": "", "audit_status": 1, "pack_spec": "101", "pack_count": "102", "unit_name": "103", "expire_date": "2024-10-24", "images": [ "https:\/\/img-hyg.hltmsp.com\/member\/image\/20240918\/c7865c97174a4eb92519edd42a98af74851785.png", "https:\/\/img-hyg.hltmsp.com\/member\/image\/20240918\/4508beb29e17b950796cc5961a88b520299817.png" ], "video": "", "video_cover": "", "is_show_video": 1, "description": "<p>spu测试spu测试spu测试<\/p>", "sort": 0, "is_gift": 1, "goods_type": 1, "sales_count": 0, "is_sales_amount_limit": 1, "recommendation": "spu测试spu测试spu测试", "is_search": 1, "is_pre_sales": 1, "is_expire": 1, "is_suite": 1, "merchant_id": 1, "business_type": 1, "keep_desc_tpl_id": 2, "notice_desc_tpl_id": 0, "del_status": 1, "create_time": "2024-10-31 10:06:43", "update_time": "2024-10-31 10:06:43", "sku_map_list": [ { "id": 710432903292862464, "spu_id": "710432902999261184", "goods_code": "", "barcode": "spu_1234561345678ywz1", "image": "https:\/\/img-hyg.hltmsp.com\/member\/image\/20240918\/c7865c97174a4eb92519edd42a98af74851785.png", "search_weight": 0, "sort": 0, "sales_count": 0, "price": "99.00", "market_price": "199.00", "cost_price": "0.00", "create_time": "2024-10-31 10:06:43", "update_time": "2024-10-31 10:06:43", "attrs": [ { "attr": "尺寸", "value": "尺寸1" }, { "attr": "颜色", "value": "颜色1" } ] }, { "id": 710432903292862465, "spu_id": "710432902999261184", "goods_code": "", "barcode": "spu_12345631345678ywz1", "image": "https:\/\/img-hyg.hltmsp.com\/member\/image\/20240918\/c7865c97174a4eb92519edd42a98af74851785.png", "search_weight": 0, "sort": 0, "sales_count": 0, "price": "99.00", "market_price": "199.00", "cost_price": "0.00", "create_time": "2024-10-31 10:06:43", "update_time": "2024-10-31 10:06:43", "attrs": [ { "attr": "尺寸", "value": "尺寸1" }, { "attr": "颜色", "value": "颜色2" } ] }, { "id": 710432903292862466, "spu_id": "710432902999261184", "goods_code": "", "barcode": "spu_123456451345678ywz1", "image": "https:\/\/img-hyg.hltmsp.com\/member\/image\/20240918\/c7865c97174a4eb92519edd42a98af74851785.png", "search_weight": 0, "sort": 0, "sales_count": 0, "price": "99.00", "market_price": "199.00", "cost_price": "0.00", "create_time": "2024-10-31 10:06:43", "update_time": "2024-10-31 10:06:43", "attrs": [ { "attr": "尺寸", "value": "尺寸2" }, { "attr": "颜色", "value": "颜色1" } ] }, { "id": 710432903292862467, "spu_id": "710432902999261184", "goods_code": "", "barcode": "spu_123456561345678ywz1", "image": "https:\/\/img-hyg.hltmsp.com\/member\/image\/20240918\/c7865c97174a4eb92519edd42a98af74851785.png", "search_weight": 0, "sort": 0, "sales_count": 0, "price": "99.00", "market_price": "199.00", "cost_price": "0.00", "create_time": "2024-10-31 10:06:43", "update_time": "2024-10-31 10:06:43", "attrs": [ { "attr": "尺寸", "value": "尺寸2" }, { "attr": "颜色", "value": "颜色2" } ] } ], "spu_attrs": [ { "attr": "尺寸", "values": [ "尺寸1", "尺寸2" ] }, { "attr": "颜色", "values": [ "颜色1", "颜色2" ] } ] }, "log_id": "710498316961951744" }
到此这篇关于element根据输入,动态生成表格的文章就介绍到这了,更多相关element动态生成表格内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!