low-ui-vue前置解读|实现一个动态列的表格组件

news2025/3/11 9:12:29

最近另一个团队正式在项目中推广内部开发的low-ui组件库了,当然 还在内部阶段,但是太慢了。作为架子的设计者和部分功能的开发者,我决定先把常见的功能通过模仿的形式公开出来。避免大家搜索无果或者使用一些框架增加学习成本。

所谓动态列的表格,就是列数不固定。
像广为使用的elementUI的 table 组件就是表头写死的,这种也叫列数固定的表格。

效果

new

当然,动态性增加了,当然要做出一定“牺牲”。这是表格组件的表头和表内容的数据格式 —— 我们把它分为两个数组传入:

数据传入

columns: [ // 表头
    { title: 'Full Name', width: 132, dataIndex: 'name', fixed: 'left' },
    { title: 'Age', width: 100, dataIndex: 'age' },
    { title: 'address1', dataIndex: 'address1', key: '1', width: 150 },
    { title: 'address2', dataIndex: 'address2', key: '2', width: 150 },
    //...
    { title: '操作', dataIndex: 'do', width: 172, fixed: 'right' }
],
data: [
    { key: 1, name: '章三', age: '18', class: '2班', address1: '111', address2: '222', address3: '333', address4: '444', address5: '555', address6: '666', address7: '777', isEdit: false },
    { key: 2, name: '章三2', age: '18', class: '2班', address1: '111', address2: '222', address3: '333', address4: '444', address5: '555', address6: '666', address7: '777', isEdit: false }
]

可以看到,“表头”数组中的 title 属性就是表头应该展示的内容,dataIndex 属性就是和“表内容” data 数组中关联的属性!它的值如果作为 key 出现在表内容数组中,则表内容这一项会展示在表格中,反之则不会。

这里也是为另一种情况考虑:表头和表内容数组都由后端提供,并不是所有返回的东西都要展示,也不是没有展示的东西都不需要,比如某一行数据的修改需要id —— 数据由后端提供,样式由前端修改。

我们继续分析数据:我们还看到了 fixed 属性和 width 属性。前者是用来判断超出表格宽度时最左侧和最右侧是否固定在两侧,这个属性只能在表头数组的第一项和最后一项中出现。后者是控制当前列的宽度。这个属性也只能在表头数组中出现!
而表内容数组中出现了另一个值:isEdit 。它用来判断当前行是否“在修改”。后面会看到,我们给表内容的每一项 v-if 了一个 input 或者自定义component。

基础版实现

表格整体当然是用了原生的 tabletrtd 实现。

虽然表头看似是一个单独的内容,但是为了样式考虑,我们并没有放在 th 中,而是作为一个普通的td,反之样式可以自定义:

<div class="table-container" ref="tableContainer" @scroll="handleScroll">
    <table>
        <colgroup>
            <col v-for="(column, index) in columns" :key="index"
                :style="{ width: column.width + 'px', minWidth: column.width + 'px' }"
                :class="{ 'fixed-left': index === 0, 'fixed-right': index === columns.length - 1 && column.fixed === 'right' }" />
        </colgroup>
        <tbody>
            <tr>
                <td v-for="(column, index) in columns" :key="index"
                    :style="{ width: column.width + 'px', minWidth: column.width + 'px' }"
                    :class="{ 'fixed-left': index === 0, 'fixed-right': index === columns.length - 1 && column.fixed === 'right', 'header-cell': true }">
                    <div class="fixed-item"><div style="display: flex;align-items: center;height: 32px;">{{ column.title }}</div></div>
                </td>
            </tr>
            <tr v-for="(row, rowIndex) in data" :key="rowIndex">
                <td v-for="(column, columnIndex) in columns" :key="columnIndex"
                    :class="{ 'fixed-left': columnIndex === 0, 'fixed-right': columnIndex === columns.length - 1 && column.fixed === 'right' }">
                    <div class="fixed-item">
                        <template v-if="column.dataIndex === 'do'">
                            <div style="display: flex;align-items: center;height: 32px;">
                                <slot :row="row"></slot>
                            </div>
                        </template>
                        <template v-else-if="!row.isEdit && !row.component"><div style="display: flex;align-items: center;height: 32px;">{{ row[column.dataIndex] }}</div></template>
                        <component :is="row.component" v-bind="row.props" v-else-if="row.component" />
                        <template v-else>
                            <div style="display: flex;align-items: center;">
                                <a-input v-model="row[column.dataIndex]" placeholder="" allow-clear />
                            </div>
                        </template>
                    </div>
                </td>
            </tr>
        </tbody>
    </table>
</div>

这操作看着很常规:

  • 在表格的HTML结构中,使用v-for指令来循环生成列和行。v-for="(column, index) in columns"用于生成列,v-for="(row, rowIndex) in data"用于生成行。
  • 每个单元格的内容由row[column.dataIndex]决定,其中column.dataIndex是列的属性名,row 是当前行的数据对象。

为了简化和防止数据冲突,我用了<colgroup><col>标签,以达到“只需要在表头数据中添加 width 即可”的效果(不需要为每个单元格单独设置样式)。
同时,从性能角度考虑:使用<colgroup><col>元素可以帮助浏览器更有效地渲染表格 —— 因为它们提供了关于表格列的元数据信息,由于列的宽度和样式是在<col>元素中定义的,浏览器可以提前计算表格的布局,从而提高渲染性能

.table-container {
    overflow-x: auto;
    max-width: 100%;
    position: relative;

    td {
        padding: 0;
        background-color: #fff;
        border-bottom: 0.9px solid #eee;

        .fixed-item {
            padding: 13px;

            &.header-cell {
                font-size: 14px;
                color: rgba(0, 0, 0, 0.85);
                font-weight: 500;
            }
        }
    }
}

.fixed-left {
    position: sticky;
    left: 0;
    width: 142px;
    align-items: center;
    z-index: 9;

    .fixed-item {
        display: block;
    }
}

.fixed-right {
    position: sticky;
    right: 0;
    width: 172px;
    align-items: center;
    z-index: 9;

    .fixed-item {
        display: block;
    }
}

.header-cell {
    background-color: #fafafa !important;
}

同时,我们监听了表格的 scroll 事件,在滚动的时候动态添加删除某个元素 —— 让表格左右侧列的阴影效果在需要的时候才展示:

handleScroll(event) {
    const container = event.target;
    const scrollLeft = container.scrollLeft;
    const maxScrollLeft = container.scrollWidth - container.clientWidth;

    // 根据滚动位置添加或移除阴影样式
    if (scrollLeft === 0) {
        container.classList.add('scroll-left');
        container.classList.remove('scroll-right');
    } else if (scrollLeft >= maxScrollLeft) {
        container.classList.add('scroll-right');
        container.classList.remove('scroll-left');
    } else {
        container.classList.add('scroll-left');
        container.classList.add('scroll-right');
    }
}

对应的css样式:

/* 添加阴影样式 */
    &.scroll-left .fixed-right {
        border-bottom: 0.1px solid transparent !important;

        .fixed-item {
            width: 100%;
            height: 100%;
            box-shadow: 1px 27px 22px 0 rgba(0, 0, 0, 0.2);
        }
    }

    &.scroll-right .fixed-left {
        border-bottom: 0.1px solid transparent !important;

        .fixed-item {
            width: 100%;
            height: 100%;
            box-shadow: -1px 27px 22px 0 rgba(0, 0, 0, 0.2);
        }
    }

到此为止,如开头所示就实现了。

使用如下:

<biaoge :columns="columns" :data="data">
    <template v-slot:default="{ row }">
        <a-button type="link">{{ row.isEdit ? '完成' : '修改' }}</a-button>
    </template>
</biaoge>

进阶?

上面的代码虽然我们只在滚动中操作了 class ,并没有直接操控 style,但它仍然是监听了scroll

能不能完全用 css 实现阴影的动态显示?能!但是再说下去就不礼貌了[doge]。给个提示:用linear-gradient!点击我的这篇文章查看相关分析 。
而且这种思想在很多地方都有使用:视觉遮盖。


这是本系列第一篇文章,有点长。关于组件库和配套工具的介绍什么的后面再说。好久没写文章了哈哈,润了润了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/917145.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

剑指 Offer 40. 最小的k个数(C++实现)

剑指 Offer 40. 最小的k个数https://leetcode.cn/problems/zui-xiao-de-kge-shu-lcof/ 法1&#xff1a;二叉堆 通过最小堆&#xff0c;直接筛选出最小的k个数 vector<int> getLeastNumbers(vector<int>& arr, int k) {priority_queue<int, vector<int>…

在Eclipse中创建javaweb工程

新建动态web工程 点击project或other之后&#xff0c;如何快速找到Dynamic Web Project 填写工程名等详细信息 也许会出现下面的对话框 项目结构图

2023第四届中国白茶始祖文化节在世界白茶发源地福鼎举办

天下白茶&#xff0c; 源于太姥。农历七月初七&#xff0c;是中国白茶始祖太姥娘娘羽化成仙的纪念日&#xff0c;8月22日上午由福鼎市茶业协会、福鼎市中国白茶始祖太姥文化研究会指导&#xff0c;由福鼎市太姥山茶业商会主办&#xff0c;由福建省天湖茶业有限公司、福建品品香…

【日常积累】Linux中vi/vim的使用

概述 vim是由vi发展演变过来的文本编辑器&#xff0c;因其具有语法高亮显示、多视窗编辑、代码折叠、支持插件等功能&#xff0c;由于其功能相比vi来说更加强大&#xff0c;所以在实际工作中的使用更加广泛。 vim工作模式 Vim具有多种工作模式&#xff0c;常用的工作模式有&…

基于swing的校园茶餐厅java jsp点餐订餐管理mysql源代码

本项目为前几天收费帮学妹做的一个项目&#xff0c;Java EE JSP项目&#xff0c;在工作环境中基本使用不到&#xff0c;但是很多学校把这个当作编程入门的项目来做&#xff0c;故分享出本项目供初学者参考。 一、项目描述 基于swing的校园茶餐厅 系统有1权限 二、主要功能 …

Spring 自动装配机制详解

文章目录 一、手动装配二、自动装配1. XML 方式2. 注解方式 一、手动装配 首先知道 Spring 装配是干了件啥事&#xff1f;我的理解&#xff0c;它就是用来解决 bean 之间依赖关系的一个手段。 比如说我这里有一个 People 类和一个 Dog 类&#xff0c;People 依赖 Dog&#xff…

uniapp - 实现卡片式胶囊单选后右上角出现 “√“ 对勾对号选中效果功能,适用于小程序h5网页app全平台通用(一键复制组件源码,开箱即用!)

效果图 uniapp全平台兼容(小程序/h5网页/app)实现点击选择后,右上角出现 √ 对号效果(角标形式展现),功能组件, 改个样式,直接复制使用该组件。 组件源码 在 components 组件文件夹下,随便建立一个 .vue 文件,一键复制下方源码。

ModaHub魔搭社区:AI Agent在网络购物场景下的AgentBench基准测试

目录 AgentBench评估哪些场景? 近日,来自清华大学、俄亥俄州立大学和加州大学伯克利分校的研究者设计了一个测试工具——AgentBench,用于评估LLM在多维度开放式生成环境中的推理能力和决策能力。研究者对25个LLM进行了全面评估,包括基于API的商业模型和开源模型。 他们发现…

发力服务业务,龙湖集团半程领跑赢在“智慧”

成立三十载&#xff0c;龙湖集团一直是房地产行业“特立独行”的存在。 一方面&#xff0c;龙湖在对外战略方面长期量入为出&#xff0c;从不背上过重的“包袱”。 不久前&#xff0c;一则消息引发市场关注&#xff1a;龙湖集团提前偿还17亿元债务&#xff0c;已基本全部还清…

solidity0.8.0的应用案例12:通用可升级合约UUPS

代理合约中选择器冲突(Selector Clash)的另一个解决办法:通用可升级代理(UUPS,universal upgradeable proxy standard)。代码由OpenZeppelin的UUPSUpgradeable简化而成,不应用于生产。 UUPS 作为透明代理的替代方案,UUPS也能解决"选择器冲突"(Selector Cl…

ARM开发(cortex-A7核中断实验)

1.实验目的&#xff1a;实现KEY1/LEY2/KE3三个按键&#xff0c;中断触发打印一句话&#xff0c;并且灯的状态取反&#xff1b; key1 ----> LED3灯状态取反&#xff1b; key2 ----> LED2灯状态取反&#xff1b; key3 ----> LED1灯状态取反&#xff1b; 2.分析框图: …

特征值分解、SVD分解在线性最小二乘解上的应用

1. 奇异值分解(SVD)原理 1.1 回顾特征值和特征向量 我们首先回顾下特征值和特征向量的定义如下&#xff1a; A x λ x Axλx Axλx其中A是一个nn的实对称矩阵&#xff0c;x是一个n维向量&#xff0c;则我们说λ是矩阵A的一个特征值&#xff0c;而x是矩阵A的特征值λ所对应的…

数据之美:探索数据可视化设计的奇妙世界

在信息时代的浪潮中&#xff0c;海量的数据正在影响着我们的生活和决策。然而&#xff0c;数据本身虽然有力量&#xff0c;但如何将其有机地呈现给我们&#xff0c;却成为了一个挑战。数据可视化设计应运而生&#xff0c;它不仅让枯燥的数字变得生动&#xff0c;还带来了一场视…

修复磁盘错误需要一小时才能完成怎么办?

“修复磁盘错误需要一小时才能完成”是一种常见的问题&#xff0c;当你遇到这个问题&#xff0c;又不想长时间等待时&#xff0c;可以尝试一下方式进行解决。 方法1. 在安全模式中解决 1. 在启动电脑看到Windows标志时&#xff0c;长按电源键强行关机&#xff0c;重复此操作三…

2023年8月第3周大模型荟萃

2023年8月第3周大模型荟萃 2023.8.22版权声明&#xff1a;本文为博主chszs的原创文章&#xff0c;未经博主允许不得转载。 1、LLM-Adapters&#xff1a;可将多种适配器集成到大语言模型 来自新加坡科技设计大学和新加坡管理大学的研究人员发布了一篇题为《LLM-Adapters: An …

Linux系统之安装OneNav个人书签管理器

Linux系统之安装OneNav个人书签管理器 一、OneNav介绍1.OneNav简介2.OneNav特点 二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、检查本地环境3.1 检查本地操作系统版本3.2 检查系统内核版本3.3 检查本地yum仓库状态 四、安装httpd服务4.1 安装httpd4.2 启动httpd服务4…

什么是客服外包?为什么越来越多的店家选择客服外包?

客服外包&#xff0c;即是将自己的客户服务体系交给更专业的团队。 1.省钱&#xff08;无需人员成本、无需设备成本、无需支付薪资&#xff09; 2.省时&#xff08;无需招聘员工、无需员工管理、无需员工培训&#xff09; 3.高效&#xff08;人工AI智能、流水线操作、专业培…

如何拉取Gitee / GitHub上的Unity项目并成功运行

前言 由于目前大部分人使用的仓库都是Gitee或者是GitHub&#xff0c;包括小编的公司所使用的项目仓库也包括了Gitee&#xff1b;我们需要学习技术栈时都会去百度或者是去GitHub上看看别人的项目观摩学习&#xff0c;可能很多小白在遇到拉取代码时出现各种问题&#xff0c;或者…

Windows wsl2支持systemd

背景 很多Linux发行版都是使用systemd来管理程序进程&#xff0c;但是在WSL中默认是用init来管理进程的。 为了符合长久的使用习惯&#xff0c;且省去不必要的学习成本&#xff0c;就在WSL的发行版&#xff08;我这里安装的是Ubuntu20.04&#xff09;中支持systemd&#xff0…

每日汇评:英镑的韧性掩盖了更广泛的疲态,英镑相关货币分析

1、尽管英国CPI数据强劲&#xff0c;但英镑/美元未能延续涨势&#xff1b; 2、欧元/英镑向下突破的时机可能已经成熟&#xff0c;英镑/日元的反弹目前正在失去动力&#xff1b; 3、英镑交叉盘的关键水平至关重要&#xff1b; 上周英国公布强劲通胀数据后&#xff0c;英镑未能…