Vue.js 元素UI el-table: 如何合并单元格并小计
Vue.js Element UI el-table: How to merge cells and subtotal them
我得到了一个像这样的原件table
| category | name | price | count | subtotal |
|----------|-------|--------|-------|----------|
| fruit | apple | 2 | 10 | 20 |
|----------|-------|--------|-------|----------|
| fruit | apple | 3 | 20 | 60 |
|----------|-------|--------|-------|----------|
| meat | pork | 4 | 10 | 40 |
|----------|-------|--------|-------|----------|
| meat | beef | 5 | 20 | 50 |
我尝试了一种方法来合并具有相同类别、名称的单元格,现在它变成了:
| category | name | price | count | subtotal |
|----------|-------|--------|-------|----------|
| | | 2 | 10 | 20 |
| fruit | apple |--------|-------|----------|
| | | 3 | 20 | 60 |
|----------|-------|--------|-------|----------|
| | | 4 | 10 | 40 |
| meat | pork |--------|-------|----------|
| | | 5 | 20 | 50 |
但是在上面table牛肉细胞消失了,我期望的是:
| category | name | price | count | subtotal |
|----------|-------|--------|-------|----------|
| | | 2 | 10 | 20 |
| fruit | apple |--------|-------|----------|
| | | 3 | 20 | 60 |
|----------|-------|--------|-------|----------|
| | pork | 4 | 10 | 40 |
| meat |-------|--------|-------|----------|
| | beef | 5 | 20 | 50 |
我还想计算相同项目的小计,如下所示:
| category | name | price | count | subtotal | subtotal2 |
|----------|-------|--------|-------|----------|-----------|
| | | 2 | 10 | 20 | |
| fruit | apple |--------|-------|----------| 80 |
| | | 3 | 20 | 60 | |
|----------|-------|--------|-------|----------|-----------|
| | pork | 4 | 10 | 40 | |
| meat |-------|--------|-------|----------| 90 |
| | beef | 5 | 20 | 50 | |
注:
我可以通过将 columnIndex === 5 添加到 objectSpanMethod 来合并 subtotal2 单元格,但数字不是我想要的:
(现在小计2只显示每一项第一行的小计,但我想要小计的总和)
| category | name | price | count | subtotal | subtotal2 |
|----------|-------|--------|-------|----------|-----------|
| | | 2 | 10 | 20 | |
| fruit | apple |--------|-------|----------| 20 |
| | | 3 | 20 | 60 | |
|----------|-------|--------|-------|----------|-----------|
| | pork | 4 | 10 | 40 | |
| meat |-------|--------|-------|----------| 40 |
| | beef | 5 | 20 | 50 | |
这是我的代码:
HTML
<div id="app">
<template>
</el-table>
<h1>DataTable<h1>
<el-table
:data="dataTable"
:span-method="objectSpanMethod"
style="width: 100%">
<el-table-column
prop="category"
label="category"
width="180">
</el-table-column>
<el-table-column
prop="name"
label="name"
width="180">
</el-table-column>
<el-table-column
prop="price"
label="price"
width="180">
</el-table-column>
<el-table-column
prop="count"
label="count"
width="180">
</el-table-column>
<el-table-column
label="subtotal"
align="center"
prop="subtotal"
width="180">
<template slot-scope="scope"> {{scope.row.subtotal=scope.row.price*scope.row.count}}
</template>
</el-table-column>
</el-table>
</template>
</div>
JS
data() {
return {
dataTable: [{
category: 'fruit',
name: 'apple',
price: 2,
count: 10,
subtotal:1
},{
category: 'fruit',
name: 'apple',
price: 3,
count: 20,
subtotal:1
},{
category: 'meat',
name: 'pork',
price: 4,
count: 10,
subtotal:1
},{
category: 'meat',
name: 'beef',
price: 5,
count: 10,
subtotal:1
}],
spanArr: [],
}
},
methods:{
onMergeLines() {
this.dataTable.forEach((item, index) => {
if (index === 0) {
this.spanArr.push(1);
this.position = 0;
} else {
if (
this.dataTable[index].category ===
this.dataTable[index - 1].category
) {
this.spanArr[this.position] += 1;
this.spanArr.push(0);
} else {
this.spanArr.push(1);
this.position = index;
}
}
});
},
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
console.log(row, column);
if (columnIndex === 0 || columnIndex === 1 ) {
const _row = this.spanArr[rowIndex];
const _col = _row > 0 ? 1 : 0;
return {
rowspan: _row,
colspan: _col,
};
}
}
},
mounted() {
this.onMergeLines();
},
}
还有 CodePen:https://codepen.io/itayueat/pen/qBPrYdV
如果你有什么想法,请告诉我table,谢谢!
我的代码比较臃肿,基本可以实现你想要的功能。如果需要,您可以进一步简化它。
var Main = {
data() {
return {
dataTable: [
{
date: "11.26",
category: "fruit",
name: "apple",
price: 2,
count: 10,
subtotal: 1
},
{
date: "11.26",
category: "fruit",
name: "apple",
price: 3,
count: 20,
subtotal: 1
},
{
date: "11.26",
category: "meat",
name: "pork",
price: 4,
count: 10,
subtotal: 1
},
{
date: "11.26",
category: "meat",
name: "beef",
price: 5,
count: 10,
subtotal: 1
},
{
date: "11.26",
category: "car",
name: "motorcycle",
price: 3,
count: 20,
subtotal: 1
},
{
date: "11.27",
category: "car",
name: "motorcycle",
price: 3,
count: 20,
subtotal: 1
},
{
date: "11.27",
category: "car",
name: "motorcycle",
price: 3,
count: 20,
subtotal: 1
}
]
};
},
created() {
this.onMergeLines();
},
methods: {
// Processing data calculation
onMergeLines() {
const propertys = ["date", "category", "name"];
const dataTable = this.dataTable;
this.dataTable = dataTable.map((item, index) => {
preRow = this.dataTable[index - 1] || {};
item.subtotal = item.count * item.price || 0;
item = diffProperty(item, index, 0);
return item;
});
function diffProperty(current, index, keyIndex) {
const key = propertys[keyIndex],
preRow = dataTable[index - 1] || {};
if (current[key] === preRow[key]) {
if (keyIndex < propertys.length) {
return diffProperty(current, index, keyIndex + 1);
} else {
current.subtotal2 = preRow.subtotal2;
return current;
}
} else {
let subtotal2 = current.count * current.price || 0;
for (let i = index + 1; i < dataTable.length; i++) {
const nextRow = dataTable[i];
console.log(
propertys.filter((prop) => current[prop] === nextRow[prop])
?.length || 0,
"c"
);
if (
(propertys.filter((prop) => current[prop] === nextRow[prop])
?.length || 0) === propertys.length
) {
subtotal2 += nextRow["count"] * nextRow["price"] || 0;
} else {
break;
}
}
current.subtotal2 = subtotal2;
return current;
}
}
},
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
//The index of the column we want to merge
if (![0, 1, 2, 6].includes(columnIndex)) {
return {
rowspan: 1,
colspan: 1
};
}
const dataTable = this.dataTable,
property = column["property"];
const tableLen = dataTable.length;
let _row = 1,
_col = 1;
const preRow = dataTable[rowIndex - 1] || {};
if (
row.date === preRow.date &&
(property === "date" || preRow[property] === row[property])
) {
_row = 0;
} else if (rowIndex + 1 < tableLen) {
for (let i = rowIndex + 1; i < tableLen; i++) {
const nextRow = dataTable[i];
if (
nextRow.date === row.date &&
(property === "date" ||
(nextRow.category === row.category &&
row[property] === nextRow[property]))
) {
_row++;
} else {
break;
}
}
}
return {
rowspan: _row,
colspan: _col
};
}
}
};
var Ctor = Vue.extend(Main);
new Ctor().$mount("#app");
@import url("//unpkg.com/element-ui@2.15.7/lib/theme-chalk/index.css");
<script src="//unpkg.com/vue/dist/vue.js"></script>
<script src="//unpkg.com/element-ui@2.15.7/lib/index.js"></script>
<div id="app">
<template>
</el-table>
<h1>DataTable<h1>
<el-table border :data="dataTable" :span-method="objectSpanMethod" style="width: 100%">
<el-table-column prop="date" label="date" width="180">
</el-table-column>
<el-table-column prop="category" label="category" width="180">
</el-table-column>
<el-table-column prop="name" label="name" width="180">
</el-table-column>
<el-table-column prop="price" label="price" width="180">
</el-table-column>
<el-table-column prop="count" label="count" width="180">
</el-table-column>
<el-table-column label="subtotal" align="center" prop="subtotal" width="180">
</el-table-column>
<el-table-column label="subtotal2" align="center" prop="subtotal2" width="180">
</el-table-column>
</el-table>
</template>
</div>
我得到了一个像这样的原件table
| category | name | price | count | subtotal |
|----------|-------|--------|-------|----------|
| fruit | apple | 2 | 10 | 20 |
|----------|-------|--------|-------|----------|
| fruit | apple | 3 | 20 | 60 |
|----------|-------|--------|-------|----------|
| meat | pork | 4 | 10 | 40 |
|----------|-------|--------|-------|----------|
| meat | beef | 5 | 20 | 50 |
我尝试了一种方法来合并具有相同类别、名称的单元格,现在它变成了:
| category | name | price | count | subtotal |
|----------|-------|--------|-------|----------|
| | | 2 | 10 | 20 |
| fruit | apple |--------|-------|----------|
| | | 3 | 20 | 60 |
|----------|-------|--------|-------|----------|
| | | 4 | 10 | 40 |
| meat | pork |--------|-------|----------|
| | | 5 | 20 | 50 |
但是在上面table牛肉细胞消失了,我期望的是:
| category | name | price | count | subtotal |
|----------|-------|--------|-------|----------|
| | | 2 | 10 | 20 |
| fruit | apple |--------|-------|----------|
| | | 3 | 20 | 60 |
|----------|-------|--------|-------|----------|
| | pork | 4 | 10 | 40 |
| meat |-------|--------|-------|----------|
| | beef | 5 | 20 | 50 |
我还想计算相同项目的小计,如下所示:
| category | name | price | count | subtotal | subtotal2 |
|----------|-------|--------|-------|----------|-----------|
| | | 2 | 10 | 20 | |
| fruit | apple |--------|-------|----------| 80 |
| | | 3 | 20 | 60 | |
|----------|-------|--------|-------|----------|-----------|
| | pork | 4 | 10 | 40 | |
| meat |-------|--------|-------|----------| 90 |
| | beef | 5 | 20 | 50 | |
注:
我可以通过将 columnIndex === 5 添加到 objectSpanMethod 来合并 subtotal2 单元格,但数字不是我想要的: (现在小计2只显示每一项第一行的小计,但我想要小计的总和)
| category | name | price | count | subtotal | subtotal2 |
|----------|-------|--------|-------|----------|-----------|
| | | 2 | 10 | 20 | |
| fruit | apple |--------|-------|----------| 20 |
| | | 3 | 20 | 60 | |
|----------|-------|--------|-------|----------|-----------|
| | pork | 4 | 10 | 40 | |
| meat |-------|--------|-------|----------| 40 |
| | beef | 5 | 20 | 50 | |
这是我的代码:
HTML
<div id="app">
<template>
</el-table>
<h1>DataTable<h1>
<el-table
:data="dataTable"
:span-method="objectSpanMethod"
style="width: 100%">
<el-table-column
prop="category"
label="category"
width="180">
</el-table-column>
<el-table-column
prop="name"
label="name"
width="180">
</el-table-column>
<el-table-column
prop="price"
label="price"
width="180">
</el-table-column>
<el-table-column
prop="count"
label="count"
width="180">
</el-table-column>
<el-table-column
label="subtotal"
align="center"
prop="subtotal"
width="180">
<template slot-scope="scope"> {{scope.row.subtotal=scope.row.price*scope.row.count}}
</template>
</el-table-column>
</el-table>
</template>
</div>
JS
data() {
return {
dataTable: [{
category: 'fruit',
name: 'apple',
price: 2,
count: 10,
subtotal:1
},{
category: 'fruit',
name: 'apple',
price: 3,
count: 20,
subtotal:1
},{
category: 'meat',
name: 'pork',
price: 4,
count: 10,
subtotal:1
},{
category: 'meat',
name: 'beef',
price: 5,
count: 10,
subtotal:1
}],
spanArr: [],
}
},
methods:{
onMergeLines() {
this.dataTable.forEach((item, index) => {
if (index === 0) {
this.spanArr.push(1);
this.position = 0;
} else {
if (
this.dataTable[index].category ===
this.dataTable[index - 1].category
) {
this.spanArr[this.position] += 1;
this.spanArr.push(0);
} else {
this.spanArr.push(1);
this.position = index;
}
}
});
},
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
console.log(row, column);
if (columnIndex === 0 || columnIndex === 1 ) {
const _row = this.spanArr[rowIndex];
const _col = _row > 0 ? 1 : 0;
return {
rowspan: _row,
colspan: _col,
};
}
}
},
mounted() {
this.onMergeLines();
},
}
还有 CodePen:https://codepen.io/itayueat/pen/qBPrYdV
如果你有什么想法,请告诉我table,谢谢!
我的代码比较臃肿,基本可以实现你想要的功能。如果需要,您可以进一步简化它。
var Main = {
data() {
return {
dataTable: [
{
date: "11.26",
category: "fruit",
name: "apple",
price: 2,
count: 10,
subtotal: 1
},
{
date: "11.26",
category: "fruit",
name: "apple",
price: 3,
count: 20,
subtotal: 1
},
{
date: "11.26",
category: "meat",
name: "pork",
price: 4,
count: 10,
subtotal: 1
},
{
date: "11.26",
category: "meat",
name: "beef",
price: 5,
count: 10,
subtotal: 1
},
{
date: "11.26",
category: "car",
name: "motorcycle",
price: 3,
count: 20,
subtotal: 1
},
{
date: "11.27",
category: "car",
name: "motorcycle",
price: 3,
count: 20,
subtotal: 1
},
{
date: "11.27",
category: "car",
name: "motorcycle",
price: 3,
count: 20,
subtotal: 1
}
]
};
},
created() {
this.onMergeLines();
},
methods: {
// Processing data calculation
onMergeLines() {
const propertys = ["date", "category", "name"];
const dataTable = this.dataTable;
this.dataTable = dataTable.map((item, index) => {
preRow = this.dataTable[index - 1] || {};
item.subtotal = item.count * item.price || 0;
item = diffProperty(item, index, 0);
return item;
});
function diffProperty(current, index, keyIndex) {
const key = propertys[keyIndex],
preRow = dataTable[index - 1] || {};
if (current[key] === preRow[key]) {
if (keyIndex < propertys.length) {
return diffProperty(current, index, keyIndex + 1);
} else {
current.subtotal2 = preRow.subtotal2;
return current;
}
} else {
let subtotal2 = current.count * current.price || 0;
for (let i = index + 1; i < dataTable.length; i++) {
const nextRow = dataTable[i];
console.log(
propertys.filter((prop) => current[prop] === nextRow[prop])
?.length || 0,
"c"
);
if (
(propertys.filter((prop) => current[prop] === nextRow[prop])
?.length || 0) === propertys.length
) {
subtotal2 += nextRow["count"] * nextRow["price"] || 0;
} else {
break;
}
}
current.subtotal2 = subtotal2;
return current;
}
}
},
objectSpanMethod({ row, column, rowIndex, columnIndex }) {
//The index of the column we want to merge
if (![0, 1, 2, 6].includes(columnIndex)) {
return {
rowspan: 1,
colspan: 1
};
}
const dataTable = this.dataTable,
property = column["property"];
const tableLen = dataTable.length;
let _row = 1,
_col = 1;
const preRow = dataTable[rowIndex - 1] || {};
if (
row.date === preRow.date &&
(property === "date" || preRow[property] === row[property])
) {
_row = 0;
} else if (rowIndex + 1 < tableLen) {
for (let i = rowIndex + 1; i < tableLen; i++) {
const nextRow = dataTable[i];
if (
nextRow.date === row.date &&
(property === "date" ||
(nextRow.category === row.category &&
row[property] === nextRow[property]))
) {
_row++;
} else {
break;
}
}
}
return {
rowspan: _row,
colspan: _col
};
}
}
};
var Ctor = Vue.extend(Main);
new Ctor().$mount("#app");
@import url("//unpkg.com/element-ui@2.15.7/lib/theme-chalk/index.css");
<script src="//unpkg.com/vue/dist/vue.js"></script>
<script src="//unpkg.com/element-ui@2.15.7/lib/index.js"></script>
<div id="app">
<template>
</el-table>
<h1>DataTable<h1>
<el-table border :data="dataTable" :span-method="objectSpanMethod" style="width: 100%">
<el-table-column prop="date" label="date" width="180">
</el-table-column>
<el-table-column prop="category" label="category" width="180">
</el-table-column>
<el-table-column prop="name" label="name" width="180">
</el-table-column>
<el-table-column prop="price" label="price" width="180">
</el-table-column>
<el-table-column prop="count" label="count" width="180">
</el-table-column>
<el-table-column label="subtotal" align="center" prop="subtotal" width="180">
</el-table-column>
<el-table-column label="subtotal2" align="center" prop="subtotal2" width="180">
</el-table-column>
</el-table>
</template>
</div>