效果图如下:
直接附上全部代码
<script setup lang="ts">
import { ref, onMounted, nextTick } from 'vue'
import { ElInput, ElMessage } from 'element-plus'
const InputRef = ref<InstanceType<typeof ElInput>>()
let table = ref([])
const arr: any = ref([]);
let buttonIndex = ref<number | ''>('')
// 添加规格
function handleAdd() {
let obj = { name: '', bool: false, count: 0, keys: [],};
arr.value.push(obj)
console.log(arr.value);
}
function handleCloseName(index:number){
console.log(arr.value,arr.value[index]);
arr.value.splice(index, 1)
table.value.splice(index, 1)
}
const inputVisible = ref(false)
//删除规格值
const handleClose = (index: number, ind: number) => {
arr.value[index].keys.splice(ind, 1)
arr.value[index].count = arr.value[index].count - 1
}
//显示规格值输入框
const showInput = (index: number) => {
if (arr.value[index].count == 3) {
ElMessage({
message: '规格值不能超过三个!',
type: 'warning',
})
return false
}
inputVisible.value = true;
buttonIndex.value = index;
arr.value[index].bool = true;
arr.value[index].count = arr.value[index].count + 1;
}
//刷新
function handleChange() {
table.value=[]
const keysList = arr.value.filter((item: any) => item.keys.length).map((item: any) => item.keys);
const titles = arr.value.map((item: any) => item.name);
if (keysList.length == 0) {
arr.value.keys = [];
return
}
console.log(keysList);
var skuList = keysList.reduce((pre: string[][], next: any) => {
var array: string[][] = [];
pre.forEach(item => {
next.forEach((ite: any) => {
array.push(item.concat([ite]))
});
});
return array
}, [[]]);
console.log(skuList, '----skuList-');
var skuTable = skuList.map((item: any) => {
const temp: any = {
price: 0,//现价
title: '',
titleArray: [],
specArray: []
};
item.forEach((val: any, index: number) => {
var key = 'id' + titles[index];
temp[key as keyof typeof temp] = val;
console.log(val + '-----');
temp.titleArray.push(val);
temp.specArray.push(titles[index] + '_' + val);
});
temp.title = temp.titleArray.join(',');
temp.specification = temp.specArray.join(',');
return temp;
})
table.value = skuTable
console.log(table.value, '----table.value');
}
//合并表格
const objectSpanMethod = ({ row, column, rowIndex, columnIndex }: any) => {
//拿到第一列要合并的行数
let specList = arr.value.filter((e: any) => e.keys?.length > 0);
if (columnIndex < specList.length - 1) {//列下标小于规格数组长度减一
let rowSpanNum = 1;//行
for (let i = columnIndex + 1; i < specList.length; i++) {
//依次拿到每一列要合并的行数
rowSpanNum *= specList[i].keys.length;
}
if (rowIndex % rowSpanNum === 0) {
//当条件成立时,即合并行数
return { rowspan: rowSpanNum, colspan: 1 }
} else {
return { rowspan: 0, colspan: 0 }
}
}
}
</script>
<template>
<div class="box">
<div class="Specification-header">
<el-row class="mb-4">
<el-button type="danger" @click="handleAdd">+添加规格</el-button>
</el-row>
</div>
<div v-for="(item, index) in arr" :key="item" class="Specification ">
<el-input v-model="item.name" placeholder="填写规格" style="width: 300px;" />
<el-icon class="input_icon" @click="handleCloseName(index)" :size="15" color="#ccc">
<CircleClose />
</el-icon>
<el-button class="button-new-tag ml-1" size="small" @click="showInput(index)">
添加规格值
</el-button>
<div class="tag">
<div class="input" v-for="(i, ind) in item.count">
<el-input v-if="inputVisible && item.bool" placeholder="填写规格值" ref="InputRef" v-model="item.keys[ind]"
:value="item.keys[ind]" style="width: 100px;" />
<el-icon class="icon-CircleClose" @click="handleClose(index, ind)" :size="15" color="#ccc">
<CircleClose />
</el-icon>
</div>
</div>
</div>
<el-card class="box-card">
<template #header>
<div class="card-header">
<el-row class="mb-4">
<el-button type="danger" @click="handleChange">刷新</el-button>
</el-row>
</div>
</template>
<el-table :data="table" :span-method="objectSpanMethod" style="width: 100%" border>
<el-table-column v-for="(item, index) in arr.filter((item: any) => item.keys.length)" width="100" align="center"
:prop="'id' + item.name" :label="item.name" />
<el-table-column label="销售价" width="180">
<template #default="scope">
<el-input-number v-model="scope.row.price" :min="1" />
</template>
</el-table-column>
</el-table>
</el-card>
</div>
</template>
<style scoped>
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.Specification {
position: relative;
width: 450px;
}
.input_icon {
position: absolute;
right: 0px;
z-index: 999;
}
.box-card {
margin-bottom: 20px;
width: 600px;
}
.input {
height: 40px;
margin: 5px;
position: relative;
}
.Specification-header{
margin: 10px 0px;
}
.icon-CircleClose {
position: absolute;
left: 90px;
z-index: 999;
}
.tag {
width: 200px;
height: 50px;
display: flex;
justify-content: start;
}
</style>
注:刷新按钮可以换成计算属性,这样就不用每次点刷新。