【low-ui-vue】实现原生可扩展动态表格组件

22e264ba9682a7be8190bc863d7cf47c.jpeg

c63d832215462fbbd6909a772a6428b1.gif

本文字数:3520

预计阅读时间:20分钟

b1912a46cf8d3f586c228bc88bafdc59.png

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

01

效果

b5a360ed003724f3607d5573190e41d9.jpeg03f1c9ad06a04eb0783593ce7ad9cefe.jpeg

c2a7c6aa611f5c5b9dd3f4432300b64e.jpeg

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

02

数据传入

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出现在表内容数组中,则表内容这一项会展示在表格中,反之则不会。

这样的数据格式也是方便了动态的特点:前端可以根据特定的场景对表头和内容单独分别处理、二次开发比如“checkbox”也可以针对数据格式做校验。

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

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

03

基础版实现

表格整体当然是用了原生的table、tr、td实现。

虽然表头看似是一个单独的内容,但是为了样式考虑,我们并没有放在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: 22px;line-height: 22px;">{{ 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: 22px;line-height: 22px;">
                                <slot :row="row"></slot>
                            </div>
                        </template>
                        <template v-else-if="!row.isEdit && !row.component"><div style="display: flex;align-items: center;height: 22px;line-height: 22px;">{{ 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 57px 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 57px 22px 0 rgba(0, 0, 0, 0.2);
        }
    }

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

使用如下:

<biaoge :columns="columns" :data="data">
    <template v-slot:default="{ row }">
        <a-button style="height: 22px;line-height: 22px;" type="link" @click="toggleEdit(row)">{{ row.isEdit ? '完成' : '修改' }}</a-button>
    </template>
</biaoge>

04

进阶?

上面的代码虽然我们只在滚动中操作了class,并没有直接操控 style,但它仍然是监听了scroll。带来了很大的性能隐患。

能不能完全用css实现阴影的动态显示?能!

什么是“阴影动态显示”?在表格内容超出可视区域左右滚动时对超出部分有阴影提示效果。

af3c46b0b72231b79dd5b4f6e29abecf.png

4.1

在CSS3的时代,我们可以在想要加滚动条的地方外包裹一层div,为其设置overflow:hidden,内部用calc()函数动态计算width使其溢出。这可以有效解决IE下兼容性问题。我们现在已经很少通过滚动条来滚动页面了(更多的是使用触摸手势),但滚动条对于元素内容可滚动的提示作用仍然是十分有用的,哪怕对于那些没有发生交互的元素也是如此;而且这种提示方式十分巧妙。

假如有一个ul、li列表:

<ul>
 <li>Ada Catlace</li>
 <li>Alan Purring</li>
 <li>Schrödingcat</li>
 <li>Tim Purrners-Lee</li>
 <li>WebKitty</li>
 <li>WebKitty</li>
 <li>Json</li>
 <li>Void</li>
</ul>

对 ul 来说:

overflow: auto;
width: 10em;
height: 8em;
padding: .3em .5em;
border: 1px solid silver;

我们用一个径向渐变在顶部添加一条阴影:

background: radial-gradient(at top, rgba(0,0,0,.2),transparent 70%) no-repeat;
background-size: 100% 15px;

现在,当我们滚动列表时,这条阴影会一直停留在相同的位置。这正是背景图像的默认行为:它的位置是相对于元素固定的!不论元素的内容是否发生了滚动。这一点也适用于background-attachment: fixed的背景图像。它们唯一的区别是,当页面滚动时,后者是相对于视口固定的。有没有办法让背景图像跟着元素的内容一起滚动呢?

现在常见的值只有inherit、scroll、fixed,但是从W3C文档中可以看到:后来为background-attachment属性增加了一个新的关键字,叫作local。如果将此属性应用到这条阴影上,它会带给我们正好相反的效果:当我们滚动到最顶端时,能看到一条阴影;但当我们向下滚动时,这条阴影就消失了。

我想到了一个很常用的hack:我们需要两层背景:一层用来生成那条阴影,另一层基本上就是一个用来遮挡阴影的白色矩形,其作用类似于遮罩层。生成阴影的那层背景将具有默认的 background-attachment值(scroll),因为我们希望它总是保持在原位。我们把遮罩背景的background-attachment属性设置为local,这样它就会在我们滚动到最顶部时盖住阴影,在向下滚动时跟着滚动,从而露出阴影。

background: linear-gradient(white 30%, transparent),
    radial-gradient(at 50% 0, rgba(0,0,0,.2),transparent 70%);
background-repeat: no-repeat;
background-size: 100% 50px, 100% 15px;
background-attachment: local, scroll;

下方的阴影只需要添加*-gradient的第一个参数,改变方向即可 —— 我们的表格组件也可以这样写:

background: linear-gradient(to right,white 30%, transparent) left / 100% 50px,
 radial-gradient(at 0 50%, rgba(0,0,0,.2),transparent 72%) left / 100% 15px,
 linear-gradient(to left, white 15px, hsla(0,0%,100%,0)) right / 100% 50px,
  radial-gradient(at right, rgba(0,0,0,.2), transparent 72%) right / 100% 15px;
background-repeat: no-repeat;
background-attachment: scroll, local, scroll, local;

620b848f649029a1a9346fb547988ffa.jpeg

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

delphi 部署设置(deployment)看不见内容的解决方法

情况说明&#xff1a; 这事&#xff0c;今年已遇到两次了&#xff08;分别是两个朋友&#xff09;&#xff0c;情况如下&#xff1a; 菜单&#xff1a;project-->deployment&#xff0c;用于我们对程序部署设置&#xff0c;特别是安卓开发需要使用到。 点开后&#xff0c…

测试辅助工具(抓包工具)的使用4 之 断点

抓包作用3&#xff08;绕过界面限制测试&#xff09; 1.为什么要绕过界面限制做测试&#xff1f; 原因&#xff1a;界面限制导致部分异常数据无法输入 2.如何绕过界面限制做测试&#xff1f; 绕过界面限制直接测试服务器 步骤&#xff1a; 1.设置断点 2.修改请求 3.修改响应…

1panel OpenResty 设置网站重定向

当我们部署网站时需要&#xff0c;输入"cheshi.com"域名回车&#xff0c;希望他自动跳转https://cheshi.com/indx/&#xff0c;而不是直接跳转https://cheshi.com时可以利用重定向来实现&#xff0c; 这里演示的是 1panel 如何设置&#xff08;nginx 貌似也是这样配…

Android中屏蔽 电源键长按、Home键、Home长按

“电源键长按”&#xff08;globalscreen&#xff09; “Home键”&#xff08;homekey&#xff09; “Home长按”&#xff08;recentapps&#xff09; 我们可以使用广播来实现&#xff0c;如&#xff1a; [java] view plain copy print ? package com.jumpinus.test; im…

C# 中的静态关键字

C# 语言中的 static 关键字用于声明静态类和静态类成员。静态类和静态类成员&#xff08;如构造函数、字段、属性、方法和事件&#xff09;在只需要一个对象&#xff08;类或类成员&#xff09;副本并在类型&#xff08;和成员&#xff09;的所有实例&#xff08;对象&#xff…

永磁同步电机FOC调试记录(一)

永磁同步电机FOC调试记录&#xff08;一&#xff09; 前言架构硬件架构软件架构 调试过程元器件选型开环控制编码器调试速度采样电流检测中断优先级的确定电流环部分烧坏IPM速度-电流环位置-电流环 结语 前言 这是我个人从零开始尝试永磁同步电机&#xff08;PMSM&#xff09;…

通用大模型 vs垂直大模型:AI界的“宫斗大戏”

科技圈最近可真热闹&#xff0c;AI大模型的“宫斗大戏”让人眼花缭乱。两个阵营&#xff1a;通用大模型和垂直大模型&#xff0c;正在上演一场激烈的“权力的游戏”。到底谁能笑到最后&#xff1f;咱们一起来“吃瓜”看看吧&#xff01; 首先&#xff0c;登场的是“全能王”通…

leetcode 动态规划(基础版)最长回文字串

题目&#xff1a; 题解&#xff1a; 首先回文子串肯定是连续的&#xff0c;如果用dp来做就需要找出一个串的所有连续子串&#xff0c;枚举一个串所有连续子串的可行方案是首先枚举子串的右端点&#xff0c;范围是&#xff08;0~s.size()-1&#xff09;,在每一个右端点中枚举左…

字节大牛耗时八个月又一力作,Android性能调优秘籍:设计思想与代码质量优化+程序性能优化+开发效率优化(全网疯传)

第一章、设计思想与代码质量优化 一、六大原则 二、设计模式 三、数据结构 四、算法 第二章、 程序性能优化 一、启动速度与执行效率优化 二、 布局检测与优化 三、 内存优化 四、耗电优化 五、网络传输与数据存储优化 六、APK 大小优化 第三章、 开发效率优化 一、…

八大排序浅入浅出

1&#xff09;选择一个增量序列t1&#xff0c;t2&#xff0c;…&#xff0c;tk&#xff0c;其中ti>tj&#xff0c;tk1&#xff1b; 2&#xff09;按增量序列个数k&#xff0c;对序列进行k 趟排序&#xff1b; 3&#xff09;每趟排序&#xff0c;根据对应的增量ti&#xff…

FlinkCDC pipeline模式 mysql-to-paimon.yaml

flinkcdc 需要引入&#xff1a; source端&#xff1a; flink-cdc-pipeline-connector-mysql-xxx.jar、mysql-connector-java-xxx.jar、 sink端&#xff1a; flink-cdc-pipeline-connector-paimon-xxx.jar flinkcdc官方提供connect包下载地址&#xff0c;pipeline模式提交作业和…

Linux查看公网IP的解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

STM32单片机BKP备份寄存器和RTC实时时钟详解

文章目录 1. Unix时间戳 2. UTC/GMT 3. 时间戳转换 4. BKP简介 5. BKP基本结构 6. RTC简介 7. RTC框架图 8. RTC基本结构 9. 代码示例 1. Unix时间戳 实时时钟&#xff0c;本质上是一个定时器&#xff0c;专门用来产生年月日时分秒。 Unix 时间戳&#xff08;Unix T…

Apple - Cocoa Event Handling Guide

本文翻译整理自&#xff1a;Cocoa Event Handling Guide&#xff08; https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/EventOverview/Introduction/Introduction.html#//apple_ref/doc/uid/10000060i 文章目录 一、导言本文件的组织另见 二、事件…

如何通过防泄密U盘,实现数据传输的安全性及可控性?

随着信息技术的发展&#xff0c;U盘作为重要的数据存储和传输工具&#xff0c;其安全性越来越受到关注。在日常办公中&#xff0c;经常会遇到这类情况&#xff1a;员工为了方便&#xff0c;随意使用U盘拷贝公司的机密资料。一旦U盘丢失或者被窃取&#xff0c;公司的机密资料就有…

Part 8.2 最短路问题

很多题目都可以转化为最短路的模型。因此&#xff0c;掌握最短路算法非常重要。 >最短路模板< 【模板】全源最短路&#xff08;Johnson&#xff09; 题目描述 给定一个包含 n n n 个结点和 m m m 条带权边的有向图&#xff0c;求所有点对间的最短路径长度&#xff…

vue-Router实现原理

http://localhost:8080/home 三、HashHistory hash("#")的作用是加载 URL 中指示网页中的位置。# 号后面的 hash值&#xff0c;可通过 window.location.hash 获取 特点&#xff1a; hash 不会被包括在 http 请求中&#xff0c;&#xff0c;对服务器端完全无用&…

《黑悟空》抢先版

当《西游记》的古老传说与现代潮流碰撞&#xff0c;一个全新的西游世界在《黑神话悟空》中缓缓展开。你&#xff0c;作为被选中的“天命人”&#xff0c;将踏上一段寻找真相的奇幻旅程。在这里&#xff0c;中国神话的深邃与东方魔幻的绚丽交织&#xff0c;构建出一个令人叹为观…

VBA技术资料MF165:关闭当前打开的所有工作簿

我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高数据的准确度。“VBA语言専攻”提供的教程一共九套&#xff0c;分为初级、中级、高级三大部分&#xff0c;教程是对VBA的系统讲解&#…

Origin较好用的科研绘图软件

推荐自己也在用的科研绘图软件Origin图所示&#xff1a; 图1 图2 图3