您现在的位置是:首页 >技术交流 >diy-table(开箱即用)网站首页技术交流

diy-table(开箱即用)

YAY_tyy 2026-07-06 00:01:05
简介diy-table(开箱即用)

此自定义表格组件基于 Vue 3 和 ElementPlus 组件库开发,提供一个易于定制的表格解决方案。

表格具备表头和表格数据展示功能,支持表头点击和行点击事件,同时可根据列定义动态生成表格内容,并能添加 tooltip 提示信息。

技术栈:Vue3+JavaScript+element-plus。

目录

使用方式

主要代码

成果展示


使用方式

<template>
    <div>
        <DiyTable
            :data="tableData"
            :columns="tableColumns"
            @select-change="handleSelectChange"
        />
    </div>
</template>

<script setup>
import { ref } from "vue";
import DiyTable from "@/components/common/diy-table/index.vue";
// 示例数据
const tableData = ref([
    { name: "John", age: 25, city: "New York" },
    { name: "Jane", age: 30, city: "Los Angeles" },
    { name: "Bob", age: 22, city: "Chicago" },
]);
// 示例列定义
const tableColumns = ref([
    {
        prop: "name",
        label: "名称",
        width: "20%",
        tooltip: (item) => `This is ${item.name}'s name`,
    },
    { prop: "age", label: "年龄", width: "50%" },
    { prop: "city", label: "城市", width: "30%" },
]);
const handleSelectChange = (item) => {
    console.log("选中的行数据:", item);
};
</script>

<style lang="less" scoped></style>

主要代码

<template>
    <div class="diy__table">
        <table>
            <thead>
                <tr>
                    <!-- 表头 -->
                    <th
                        v-for="column in columns"
                        :key="column.prop"
                        :style="{ width: column.width }"
                        @click="handleHeaderClick(column)"
                    >
                        {{ column.label }}
                    </th>
                </tr>
            </thead>
            <tbody align="center" valign="center">
                <!-- 表格数据 -->
                <tr
                    v-for="(item, index) in data"
                    :key="index"
                    :class="{ 'selected-row': selectedIndex === index }"
                    @click="handleRowClick(item)"
                >
                    <td
                        v-for="column in columns"
                        :key="column.prop"
                        :style="{ width: column.width }"
                    >
                        <!-- 如果 column 有 tooltip 属性,则添加 el-tooltip -->
                        <el-tooltip
                            v-if="column.tooltip"
                            :content="column.tooltip(item)"
                            placement="top"
                            effect="light"
                        >
                            <span>{{ item[column.prop] }}</span>
                        </el-tooltip>
                        <span v-else>{{ item[column.prop] }}</span>
                    </td>
                </tr>
            </tbody>
        </table>
    </div>
</template>

<script setup>
import { ref, defineProps, defineEmits } from "vue";
import { ElTooltip } from "element-plus"; // 引入 ElTooltip 组件

// 定义 props,接收父组件传递的数据和列定义
const props = defineProps({
    data: {
        type: Array, // 表格数据
        required: true,
    },
    columns: {
        type: Array, // 表格列定义
        required: true,
    },
});

// 定义一个响应式变量来存储当前选中的行索引
const selectedIndex = ref(-1);

// 定义事件
const emits = defineEmits(["select-change", "header-click"]);

// 处理行点击事件
const handleRowClick = (item) => {
    selectedIndex.value = props.data.indexOf(item);
    // 触发 select-change 事件并传递整个 item
    emits("select-change", item);
};

// 处理表头点击事件
const handleHeaderClick = (column) => {
    // 触发 header-click 事件并传递被点击的列信息
    emits("header-click", column);
};
</script>

<style scoped lang="less">
.diy__table {
    table {
        background: rgba(49, 92, 155, 0.2);
        border-radius: 4px 4px 4px 4px;
        border: 1px solid rgba(255, 255, 255, 0.2);
        box-shadow: 0px 1px 1px 0px rgba(0, 0, 0, 0.25);
        border-collapse: collapse;
        border-spacing: 0;
        margin: 0;
        padding: 0;
        th,
        td {
            padding: 0;
        }
        thead {
            display: table;
            width: 100%;
            table-layout: fixed;
            tr {
                margin: 0;
                padding: 0;
                th {
                    font-weight: 500;
                    font-size: 14px;
                    color: rgba(255, 255, 255, 0.6);
                    line-height: 20px;
                    background: rgba(0, 99, 255, 0.2);
                    padding: 6px;
                    white-space: nowrap;
                    border-bottom: 2px solid #5374a8;
                }
            }
        }

        tbody {
            display: block;
            height: 190px;
            overflow-y: auto;
            tr {
                display: table;
                width: 100%;
                font-weight: 500;
                font-size: 14px;
                color: #ffffff;
                line-height: 20px;
                table-layout: fixed;
                td {
                    padding: 6px;
                }
            }
            tr:nth-child(even) {
                background: rgba(62, 127, 207, 0.2);
            }
            tr:nth-child(even).selected-row {
                background: rgba(52, 114, 212, 0.8);
            }
            // 选中行的样式
            .selected-row {
                background: rgba(52, 114, 212, 0.8);
            }
        }
        thead tr th {
            position: sticky;
            top: 0;
        }
    }
}
</style>

成果展示

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。