我正在尝试为我的应用程序中的多个视图创建标准化的表系统。为了让设计师可以忽略整个过程,我们决定在表上有两个标题。问题就变成了:
向表添加第二个标题的最佳方法是什么,该标题将调整大小以适合列数?
该表包含一堆行和列。但是表格可以隐藏和显示列。每当我隐藏另一列时,我都需要新的标头来调整其大小;如果隐藏在它下面的所有列,则都需要隐藏它自己。
这是组件的内容:
<template>
<!-- Basic table. Adapt it's content and size based on the props received -->
<div class="table-content">
<a>
<!-- export table for Excel -->
<JsonExcel :data="sortedContent" style="width: 50px;">
<i class="fa fa-file-excel"></i>
</JsonExcel>
</a>
<!-- bouton pour afficher le panneau des settings -->
<button @click="togglePanel()">settings</button>
<table class="c-base-table" :class="tableName">
<!-- Opening table -->
<thead>
<!-- Header table -->
<tr>
<!-- Show columns titles -->
<th
v-for="key in columns"
@click="sortBy(key)"
:class="[
columnsShown.includes(key) ? '' : 'hidden-col',
key,
{active: sortKey == key}
]"
:key="key"
>
{{ columnsNames[key] | capitalize }}
<span
class="arrow"
:class="sortOrders[key] > 0 ? 'asc' : 'dsc'"
></span>
</th>
</tr>
</thead>
<tbody>
<!-- table content -->
<tr v-for="entry in sortedContent" :key="entry.id">
<!-- content sorted depending on the chosen column -->
<td
v-for="key in columns"
:class="[columnsShown.includes(key) ? '' : 'hidden-col', key]"
:key="entry.id + key"
>
{{ entry[key] | limitDecimal }}
</td>
</tr>
<tr v-if="hasTotal">
<!-- if an array called "columnToTotal" is given, it will calculate the total of the chosen columns -->
<td
v-for="key in columns"
:class="[columnsShown.includes(key) ? '' : 'hidden-col', key]"
:key="key"
>
<div v-if="columnsToTotal.includes(key)">
{{ sumColumn[key] }}
</div>
</td>
</tr>
</tbody>
</table>
<!-- If there are more than [rowPerPage] row in the table, start the pagination -->
<div v-if="listLength > rowPerPage">
<Pagination
@changePage="changePage"
:totalNumPages="totalNumPages"
:numPage="numPage"
></Pagination>
</div>
<!-- settings -->
<div class="panel-config" v-show="panelIsShown">
<ul>
<!-- list of columns with a checkbox to show/hide that column -->
<li v-for="key in columns" :class="key" :key="key">
<input
type="checkbox"
:id="key"
:value="key"
v-model="columnsShown"
/>
{{ columnsNames[key] | capitalize }}
</li>
</ul>
<!-- If asked, it will show a set of datepickers to use update the infos -->
<div v-if="toggleDate" id="dateSettings">
<Datepicker v-model="beginDate"></Datepicker>
<Datepicker v-model="endDate"></Datepicker>
<button @click="updateContent">update</button>
</div>
<hr />
<slot></slot>
</div>
</div>
</template>
<script>
// Imports
import {isNumber} from 'util';
import Datepicker from 'gso-datepicker';
import JsonExcel from 'vue-json-excel';
import Pagination from './pagination.vue';
export default {
name: 'baseTable',
components: {
JsonExcel,
Pagination,
Datepicker
},
filters: {
// capitalize the 1st letter
capitalize: function(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
},
// limit value to 2 decimal IF it is a decimal number
limitDecimal: function(value) {
if (isNumber(value) && value !== Math.floor(value)) {
return parseFloat(value).toFixed(2);
}
return value;
}
},
// parameters received by the component
props: [
'columns',
'tableContent',
'tableName',
'columnsToTotal',
'columnsNames',
'columnsShown',
'toggleDate'
],
data: function() {
var sortOrders = {};
this.columns.forEach(function(key) {
sortOrders[key] = 1;
});
return {
// initialization
sortKey: '',
sortOrders: sortOrders,
panelIsShown: false,
beginDate: new Date(),
endDate: new Date(),
numPage: 1, // current page for pagination
rowPerPage: 20 // max number of row per page
};
},
computed: {
// Sorted content
sortedContent: function() {
var sortKey = this.sortKey;
var order = this.sortOrders[sortKey] || 1;
var tableContent = this.tableContent;
if (sortKey) {
tableContent = tableContent.slice().sort(function(a, b) {
a = a[sortKey];
b = b[sortKey];
return (a === b ? 0 : a > b ? 1 : -1) * order;
});
}
tableContent = tableContent.slice(
(this.numPage - 1) * this.rowPerPage,
this.numPage * this.rowPerPage
);
return tableContent;
},
// calculate totals of selected columns
sumColumn: function() {
const sumTot = [];
const sortedContent = this.sortedContent;
this.columnsToTotal.forEach(function(column) {
sumTot[column] = sortedContent.reduce(function(sum, item) {
return sum + item[column];
}, 0);
});
return sumTot;
},
// check if making total is necessary
hasTotal: function() {
return this.columnsToTotal !== undefined;
},
// check if columns have a name
hasNames: function() {
return this.columnsNames !== undefined;
},
// calculate the number of rows
listLength: function() {
return this.tableContent.length;
},
// calculate the number of page required for these rows
totalNumPages: function() {
return Math.ceil(this.listLength / this.rowPerPage);
}
},
watch: {
columns: function() {
var sortOrders = {};
this.columns.forEach(function(key) {
sortOrders[key] = 1;
});
this.sortOrders = sortOrders;
}
},
methods: {
// Sorting of the table
sortBy: function(key) {
this.sortKey = key;
if (this.sortOrders[key] === undefined) {
this.sortOrders[key] = 1;
}
this.sortOrders[key] = this.sortOrders[key] * -1;
},
// hide/show settings
togglePanel: function() {
this.panelIsShown = !this.panelIsShown;
},
// send beginDate and endDate to parent to update the content
updateContent: function() {
var beginDate = this.beginDate.toISOString().split('T')[0];
var endDate = this.endDate.toISOString().split('T')[0];
this.$emit('updateContent', beginDate, endDate);
},
// change page number
changePage: function(numPage) {
this.numPage = numPage;
}
}
};
</script>
例如,如果我发送以下内容作为标题:
columns: [
'agentName',
'employersAmount',
'contractsAmount',
'contractsAmountPrestaWeb',
'contractsAmountPresta',
'contractsAmountPrestaLight',
'contractsAmountPaper',
'employersAmountPrestaWeb',
'employersAmountPresta',
'employersAmountPrestaLight',
'employersAmountPaper',
'contractsPercentPrestaWeb',
'contractsPercentPresta',
'contractsPercentPrestaLight',
'contractsPercentPaper',
'employerPercentPrestaWeb',
'employerPercentPresta',
'employerPercentPrestaLight',
'employerPercentPapier',
'officeName'
]
columnsNames: {
agentName: 'Gestionnaire',
employersAmount: '# Dossiers',
contractsAmount: '# Contrats',
contractsAmountPrestaWeb: '# Contrats PW',
contractsAmountPresta: '# Contrats PW',
contractsAmountPrestaLight: '# Contrats PL',
contractsAmountPaper: '# Contrats pa',
employersAmountPrestaWeb: '# Dossiers PW',
employersAmountPresta: '# Dossiers Pr',
employersAmountPrestaLight: '# Dossiers PL',
employersAmountPaper: '# Dossiers pa',
contractsPercentPrestaWeb: '% Contrats PW',
contractsPercentPresta: '% Contrats Pr',
contractsPercentPrestaLight: '% Contrats PL',
contractsPercentPaper: '% Contrats pa',
employerPercentPrestaWeb: '% Dossiers PW',
employerPercentPresta: '% Dossiers Pr',
employerPercentPrestaLight: '% Dossiers PL',
employerPercentPapier: '% Dossiers pa',
officeName: 'Bureau'
}
我得到以下结果:
<table>
<tr>
<th>Gestionnaire</th>
<th># Dossiers</th>
<th># Contrats</th>
<th># Contrats PW</th>
<th># Contrats PL</th>
<th># Contrats Pr</th>
<th># Contrats Pa</th>
<th># Dossiers PW</th>
<th># Dossiers PL</th>
<th># Dossiers Pr</th>
<th># Dossiers Pa</th>
<th>% Contrats PW</th>
<th>% Contrats PL</th>
<th>% Contrats Pr</th>
<th>% Contrats Pa</th>
<th>% Dossiers PW</th>
<th>% Dossiers PL</th>
<th>% Dossiers Pr</th>
<th>% Dossiers Pa</th>
<th>Bureau</th>
</tr>
</table>
尽管我希望遵循这些原则:
<table>
<tr>
<th rowspan="2">Gestionnaire</th>
<th colspan="9">Dossiers</th>
<th colspan="9">Contrats</th>
<th rowspan="2">Bureau</th>
</tr>
<tr>
<th>total</th>
<th># PW</th>
<th># PL</th>
<th># Pr</th>
<th># Pa</th>
<th>% PW</th>
<th>% PL</th>
<th>% Pr</th>
<th>% Pa</th>
<th>total</th>
<th># PW</th>
<th># PL</th>
<th># Pr</th>
<th># Pa</th>
<th>% PW</th>
<th>% PL</th>
<th>% Pr</th>
<th>% Pa</th>
</tr>
</table>
知道我可以(通过columnsShown数组)隐藏一些列,并且我需要colspan进行更新以适合相应列的数量。
为此更改代码的最佳方法是什么?我仍然需要使表看起来像第一个表,但是也许可以通过更改一些道具,或者通过实际发送一些道具,来将行为更改为具有双标头。我当时想添加一个新的道具,例如
columnsContainer: [
Files:{
'employersAmount',
'employersAmountPrestaWeb',
'employersAmountPresta',
'employersAmountPrestaLight',
'employersAmountPaper','employerPercentPrestaWeb',
'employerPercentPresta',
'employerPercentPrestaLight',
'employerPercentPapier'
},
Contracts:{
'contractsAmount',
'contractsAmountPrestaWeb',
'contractsAmountPresta',
'contractsAmountPrestaLight',
'contractsAmountPaper',
'contractsPercentPrestaWeb',
'contractsPercentPresta',
'contractsPercentPrestaLight',
'contractsPercentPaper',
}
]
如果它是空的,则做一个简单的标题,而如果它已填满东西,请查看键并根据该键组织标题。