vue3 table 可编辑表格

发布于:2025-08-01 ⋅ 阅读:(18) ⋅ 点赞:(0)

内容摘要:

本文介绍了在Vue3中使用vxe-table插件实现可编辑表格的封装方案。通过两个示例展示了不同表头结构的实现:第一个表格采用单级表头,包含合并单元格和可编辑功能;第二个表格实现多级表头结构,包含子表头和单元格编辑控制。代码中通过reactive定义表格数据和配置,使用pointExists方法控制可编辑单元格范围,并提供了样式自定义。这种封装方式相比原生element组件能更好地支持复杂表格需求。

背景:

在vue3项目中,根据客户的需求,需要实现不同的表格并且表格要可以编辑。可编辑表格,有点像form表单,要实现可以在表格中输入数据,table的壳子,form的业务。使用element组件实现效果不太好实现,根据百度找到了这个插件vxe-table

安装的版本号分别是:

    "vxe-pc-ui": "^4.7.14",

    "vxe-table": "^4.14.4",

这里封装了一个示例,包括二级表头、多级表头的封装。

参考博文:点击跳转

实现效果:

直接复制代码看一下效果吧。。。 

完整代码:

<template>
    <div>
        <div class="container1 infoState">
            <vxe-table :data="infoState.tableData" empty-text="没有更多数据了!" :loading="infoState.loading" :border="'full'"
                :align="'center'" :merge-cells="infoState.mergeCells" :edit-config="infoState.editConfig">
                <vxe-colgroup title="船舶信息" :header-cell-class-name="'header-cell'">
                    <vxe-column v-for="(item, index) in infoState.tableList" :field="item.prop" :title="item.label"
                        :width="item.width" :key="index" :edit-render="{ name: 'VxeInput' }"></vxe-column>
                </vxe-colgroup>
            </vxe-table>
        </div>
        <div class="container1 incomeState">
            <vxe-table :data="incomeState.tableData" empty-text="没有更多数据了!" :loading="incomeState.loading"
                :border="'full'" :align="'center'" :merge-cells="incomeState.mergeCells"
                :edit-config="incomeState.editConfig">
                <vxe-colgroup title="航次收入" :header-cell-class-name="'header-cell'">
                    <template v-for="(item, index) in incomeState.tableList" :key="index">
                        <vxe-column :field="item.prop" :title="item.label" :width="item.width" v-if="!item.children"
                            :edit-render="{ name: 'VxeInput', placeholder: '请点击输入...' }"></vxe-column>
                        <vxe-colgroup v-else :title="item.label" :header-cell-class-name="'header-cell'">
                            <vxe-column v-for="(item2, index2) in item.children" :field="item2.prop"
                                :title="item2.label" :width="item2.width" :key="index2"
                                :edit-render="{ name: 'VxeInput', placeholder: '请点击输入...' }"></vxe-column>
                        </vxe-colgroup>
                    </template>
                </vxe-colgroup>
            </vxe-table>
        </div>
    </div>
</template>

<script setup>
import { reactive, ref, watch } from "vue";
const pointExists = (points, target) => {
    for (let i = 0; i < points.length; i++) {
        if (points[i][0] === target[0] && points[i][1] === target[1]) {
            return true;
        }
    }
    return false;
}
const infoState = reactive({
    loading: false,
    tableData: [
        {
            id: 10001,
            name: "胜利号1168",
            cargoType: "",
            shipLook: "",
            shipTime: "",
            height: "",
            jHeight: "",
            length: "",
            width: "",
            xWidth: "",
            myType: "夏季吃水",
            draft: ""
        },
        {
            id: 10002,
            name: "航行方式",
            cargoType: "航速",
            shipLook: "航次日耗",
            shipTime: "航次日耗",
            height: "航次日耗",
            jHeight: "停泊日耗",
            length: "停泊日耗",
            width: "停泊日耗",
            xWidth: "31",
            myType: "热带吃水",
            draft: ""
        },
        {
            id: 10003,
            name: "航行方式",
            cargoType: "航速",
            shipLook: "FO(CST180)",
            shipTime: "DO(4#)",
            height: "GO(0#)",
            jHeight: "FO(CST180)",
            length: "DO(4#)",
            width: "GO(0#)",
            xWidth: "31",
            myType: "载重吨",
            draft: ""
        },
        {
            id: 10004,
            name: "设计航速",
            cargoType: "",
            shipLook: "",
            shipTime: "",
            height: "",
            jHeight: "",
            length: "",
            width: "",
            xWidth: "",
            myType: "散装舱容",
            draft: ""
        },
        {
            id: 10005,
            name: "经济航速",
            cargoType: "",
            shipLook: "",
            shipTime: "",
            height: "",
            jHeight: "",
            length: "",
            width: "",
            xWidth: "",
            myType: "TPC",
            draft: ""
        },
    ],
    tableList: [
        {
            label: "船名",
            prop: "name",
            width: '10%',
        },
        {
            label: "航次",
            prop: "hangci",
            width: '12%',
        },
        {
            label: "船型",
            prop: "shipLook",
            width: '10%',
        },
        {
            label: "交船日期",
            prop: "shipTime",
            width: '10%',
        },
        {
            label: "总吨",
            prop: "height",
            width: '10%',
        },
        {
            label: "净吨",
            prop: "jHeight",
            width: '10%',
        },
        {
            label: "总长",
            prop: "length",
            width: '8%',
        },
        {
            label: "型宽",
            prop: "width",
            width: '8%',
        },
        {
            label: "其它信息",
            prop: "myType",
            width: '8%',
        },
        {
            label: "",
            prop: "draft",
            width: '14%',
        },
    ],
    mergeCells: [
        {
            row: 1,
            col: 0,
            rowspan: 2,
            colspan: 1
        },
        {
            row: 1,
            col: 1,
            rowspan: 2,
            colspan: 1
        },
        {
            row: 1,
            col: 2,
            rowspan: 1,
            colspan: 3
        },
        {
            row: 1,
            col: 5,
            rowspan: 1,
            colspan: 3
        },
    ],
    points: [
        [0, 0],
        [0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [0, 6], [0, 7], [0, 9],
        [1, 1], [1, 9],
        [2, 9],
        [3, 1], [3, 2], [3, 3], [3, 4], [3, 5], [3, 6], [3, 7], [3, 9],
        [4, 1], [4, 2], [4, 3], [4, 4], [4, 5], [4, 6], [4, 7], [4, 9],
    ],
    editConfig: {
        trigger: 'click',
        mode: 'cell',
        showIcon: false,
        beforeEditMethod: ({ row, rowIndex, column, columnIndex }) => {
            const _point = [rowIndex, columnIndex];
            return pointExists(infoState.points, _point);
        }
    },
});
const incomeState = reactive({
    loading: false,
    isHeader: false,
    tableData: [
        {
            id: 10001,
            weikong: "预算",
            actualQuantity: "",
            cargoVolume: "",
            freight: "",
            actualQuantity: "",
            actualQuantity: "",
            actualQuantity: "",
            fo_hcrh: "",
            do_hcrh: "",
            go_hcrh: "",
            total: ""
        },
    ],
    tableList: [
        {
            label: "",
            prop: "weikong",
            width: "10%",
        },
        {
            label: "货量",
            prop: "cargoVolume",
            width: "10%",
        },
        {
            label: "运费",
            prop: "freight",
            width: "10%",
        },
        {
            label: "滞期费",
            prop: "actualQuantity",
            width: "30%",
            children: [
                {
                    label: "装港停时",
                    prop: "fo_hcrh",
                    width: 180,
                },
                {
                    label: "卸港停时",
                    prop: "do_hcrh",
                    width: 180,
                },
                {
                    label: "滞期费",
                    prop: "go_hcrh",
                    width: 180,
                },
            ],
        },
        {
            label: "其它收入",
            prop: "actualQuantity",
            width: "30%",
            children: [
                {
                    label: "亏舱费",
                    prop: "fo_hcrh",
                    width: 180,
                },
                {
                    label: "",
                    prop: "do_hcrh",
                    width: 180,
                },
                {
                    label: "",
                    prop: "go_hcrh",
                    width: 180,
                },
            ],
        },
        {
            label: "合计",
            prop: "total",
            width: "12.5%",
        },
    ],
    points: [
        [0, 0],
        [0, 1], [0, 2], [0, 3], [0, 4], [0, 5], [0, 6], [0, 7], [0, 9],
        [1, 9],
        [2, 9],
        [3, 0],
        [3, 1], [3, 2], [3, 3], [3, 4], [3, 5], [3, 6], [3, 7], [3, 9],
    ],
    editConfig: {
        trigger: 'click',
        mode: 'cell',
        showIcon: false,
        beforeEditMethod: ({ row, rowIndex, column, columnIndex }) => {
            console.log('beforeEditMethod>>>', row, rowIndex, column, columnIndex);
            const _point = [rowIndex, columnIndex];
            return pointExists(incomeState.points, _point);
        }
    },
});
</script>

<style scoped>
:deep(.vxe-header--row) {
    background-color: #def0ff;

    &:last-child {
        background-color: #f5f9ff;
    }
}

.infoState {
    height: 400px;
}

.incomeState {
    height: 187px;
}
</style>