如何在我的表格组件上动态添加第二行标题

时间:2019-04-29 14:14:34

标签: vue.js html-table vue-component tableheader

我正在尝试为我的应用程序中的多个视图创建标准化的表系统。为了让设计师可以忽略整个过程,我们决定在表上有两个标题。问题就变成了:

向表添加第二个标题的最佳方法是什么,该标题将调整大小以适合列数?

该表包含一堆行和列。但是表格可以隐藏和显示列。每当我隐藏另一列时,我都需要新的标头来调整其大小;如果隐藏在它下面的所有列,则都需要隐藏它自己。

这是组件的内容:

<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',
    }
]

如果它是空的,则做一个简单的标题,而如果它已填满东西,请查看键并根据该键组织标题。

0 个答案:

没有答案