效果展示
效果说明
输入商品的颜色、尺寸后点击添加按钮,即可将对应的商品信息添加到下方的表格当中,表格中除了会显示商品的颜色和尺寸之外,还会显示商品的价格和库存,并且可以对商品的价格和库存进行修改,并且根据颜色进行分组将相同颜色值的数据都会添加在一个大行当中。
效果实现代码
第一步:创建项目
yarn create vite sku
第二步:安装项目所需要的依赖
yarn
yarn add sass sass-loader
yarn add vue-router
yarn add path
yarn add element-plus
yarn add -D unplugin-auto-import
yarn add unplugin-vue-components@0.26.0
注意:
安装 unplugin-vue-components 的时候要指导其版本为0.26.0,否则默认安装的为最新版本0.27.0,等到配置完element-plus组件的自动导入时会导致样式不生效的问题。
第三步: 配置别名@,以及配置element-plus的自动导入
vue.configchuan.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import path from 'path';
import AutoImport from 'unplugin-auto-import/vite';
import Components from 'unplugin-vue-components/vite';
import { ElementPlusResolver } from 'unplugin-vue-components/resolvers';
export default defineConfig({
plugins: [
vue(),
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
resolve: {
alias: {
'@': path.resolve(__dirname, 'src')
}
},
});
第四步:创建Home页面并配置路由文件
src/router/index.js
import {createRouter,createWebHistory} from 'vue-router'
const routes = [
{
path: '/',
component:()=>import('@/views/Home.vue')
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
第五步:引入路由文件
main.js
import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
createApp(App).use(router).mount('#app')
第六步:在创建的Home页面中编写代码
<template>
<div>
<div>
<el-input v-model="color" placeholder="请输入颜色" />
<el-input v-model="size" placeholder="行输入型号" />
<el-button type="primary" @click="add">添加</el-button>
</div>
<div>
<table width="1000" cellspacing="0">
<!-- 表格的标题部分 -->
<tr>
<th
v-for="(item, index) in showThData"
:key="index"
class="thStyle"
:style="{ borderLeft: index === 0 ? '1px solid #eee' : '' }"
>
{{ item.title }}
</th>
</tr>
<tr v-if="!tableData.length">
<td :colspan="thData.length" class="noData">暂无数据</td>
</tr>
<!-- 表格的内容主题部分 -->
<tr v-for="(obj, key) in groupData" :key="key" class="size tdbgColor">
<!-- 颜色列 -->
<td class="colorBorder" :style="tdStyle('color')">{{ key }}</td>
<!-- 尺寸列 -->
<td>
<!-- 每种尺寸独占一行 -->
<tr v-for="(item, index) in obj" :key="index">
<td :style="tdStyle('size')">{{ item.size }}</td>
</tr>
</td>
<!-- 价格列 -->
<td>
<!-- 每种尺寸的价格独占一行 -->
<tr v-for="(item, index) in obj" :key="index">
<td :style="tdStyle('size')">
<!--
设置 precision 属性可以控制数值精度,接收一个 Number
当设置number为2的时候为保留两位小数
-->
<el-input-number
v-model="item.price"
:precision="2"
:min="0"
@change="handleChange"
/>
</td>
</tr>
</td>
<!-- 库存列 -->
<td>
<!-- 每种尺寸的库存独占一行 -->
<tr v-for="(item, index) in obj" :key="index">
<td :style="tdStyle('size')">
<!--
设置 precision 属性可以控制数值精度,接收一个 Number
当设置number为0的时候为保留整数【四舍五入】
-->
<el-input-number
v-model="item.stock"
:precision="0"
:min="0"
@change="handleChange"
/>
</td>
</tr>
</td>
</tr>
</table>
</div>
<!-- <el-button type="primary" @click="submit">提交</el-button>
<div v-show="isShow">{{ showGroupData }}</div> -->
</div>
</template>
<script setup>
import { ref } from "vue";
const handleChange = (value) => {
console.log(value);
};
const tableData = ref([]);
const thData = ref([
{ title: "颜色", text: "color" },
{ title: "尺寸", text: "size" },
{ title: "价格", text: "price" },
{ title: "库存", text: "stock" },
]);
const showThData = ref(thData);
const color = ref(""); //颜色
const size = ref(""); //尺寸
const groupData = ref({}); //将添加的数据按照颜色进行分组
const showGroupData = ref({});
// 点击添加按钮将数据添加到下方表格中
const add = () => {
tableData.value.push({
color: color.value,
size: size.value,
price: 0,
stock: 0,
});
sort();
};
// 对添加的数据进行分组处理,当多个颜色的值相同时按照第一个出现的位置进行排序
const sort = () => {
// 创建一个映射表来记录每种颜色首次出现的索引
const colorIndices = new Map();
tableData.value.forEach((item, index) => {
if (!colorIndices.has(item.color)) {
colorIndices.set(item.color, index);
}
});
// 根据颜色首次出现的索引进行排序
tableData.value.sort((a, b) => {
// 获取a和b的颜色首次出现的索引
const indexA = colorIndices.get(a.color);
const indexB = colorIndices.get(b.color);
// 如果首次出现的索引相同,则保持原始顺序(可选,取决于具体需求)
// 这里假设原始顺序应当保持,如果不需要保持则直接返回 indexA - indexB 即可
return indexA === indexB
? tableData.value.indexOf(a) - tableData.value.indexOf(b)
: indexA - indexB;
});
// 使用reduce方法对数据进行分组处理
groupData.value = tableData.value.reduce((acc, curr) => {
const color = curr.color;
if (!acc[color]) {
acc[color] = [];
}
acc[color].push(curr);
return acc;
}, {});
};
// 单元格的样式设置
const tdStyle = (type) => {
let style = { borderBottom: "1px solid #eee" };
if (type === "color") {
style.borderLeft = "1px solid #eee";
} else {
style.borderRight = "1px solid #eee";
}
return style;
};
const isShow = ref(false); //数据是否显示
// 点击提交按钮将数据显示在下方
const submit = () => {
showGroupData.value = { ...groupData.value, title: thData.value };
isShow.value = true;
};
</script>
<style lang="scss" scoped>
.el-input {
margin: 10px;
width: 200px;
}
table {
margin: 10px;
text-align: center;
th,
td {
width: 250px;
height: 50px;
}
th {
color: #888;
}
.thStyle {
border: 1px solid #eee;
border-left: none;
}
.size {
border: none;
}
// 设置样式表格隔行显示背景色
.tdbgColor:nth-child(2n + 1) {
background: #d1edff59;
}
}
.colorBorder {
border-right: 1px solid #eee;
}
.price {
border-right: 1px solid #eee;
border-bottom: 1px solid #eee;
}
.noData {
border: 1px solid #eee;
border-top: none;
color: #ccc;
}
</style>
通过以上步骤即可实现效果图中所展示的效果
由于对于element-plus组件库中的el-table的合并单元格的方法没有写明白所以就用了原生的table书写的,如果有哪位大佬可以使用el-table实现该效果,还请不吝赐教。