【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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#基于SkiaSharp实现印章管理(2)

上一篇文章最后提到基于System.Text.Json能够序列化SKColor对象&#xff0c;但是反序列化时却无法解析本地json数据。换成Newtonsoft.Json进行序列化和反序列化也是类似的问题。   通过百度及查看微软的帮助文档&#xff0c;上述情况下需自定义转换类以处理SKColor类型数据的…

Vite响应Ajax请求

Vite响应Ajax请求 陈拓 2024/06/20-2024/06/24 1. 概述 http-server、live-server 等常用于本地测试和开发的http服务器不能很好的支持 ES 模块&#xff0c;在测试ES 模块时浏览器控制台经常显示错误&#xff1a; Failed to load module script: Expected a JavaScript modu…

C++用Crow实现一个简单的Web程序,实现动态页面,向页面中输入数据并展示

Crow是一个轻量级、快速的C微框架&#xff0c;用于构建Web应用程序和RESTful API。 将处理前端页面的POST请求以添加数据的逻辑添加到 /submit 路由中&#xff0c;并添加了一个新的路由 / 用于返回包含输入框、按钮和表格的完整页面。当用户向表格添加数据时&#xff0c;JavaS…

021.合并两个有序链表,递归和遍历

题意 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 难度 简单 标签 链表、排序 示例 输入&#xff1a;l1 [1,2,4], l2 [1,3,4] 输出&#xff1a;[1,1,2,3,4,4]输入&#xff1a;l1 [], l2 [] 输出&#xff1a;[]…

PCM、WAV,立体声,单声道,正弦波等音频素材

1&#xff09;PCM、WAV音频素材&#xff0c;分享给将要学习或者正在学习audio开发的同学。 2&#xff09;内容属于原创&#xff0c;若转载&#xff0c;请说明出处。 3&#xff09;提供相关问题有偿答疑和支持。 常用的Audio PCM WAV不同采样率&#xff0c;不同采样深度&#…

CubeFS - 新一代云原生存储系统

CubeFS 是一种新一代云原生存储系统,支持 S3、HDFS 和 POSIX 等访问协议,支持多副本与纠删码两种存储引擎,为用户提供多租户、 多 AZ 部署以及跨区域复制等多种特性。 官方文档 CubeFS 作为一个云原生的分布式存储平台,提供了多种访问协议,因此其应用场景也非常广泛,下面…

DataGrip 2024 po for Mac 数据库管理工具解

Mac分享吧 文章目录 效果一、下载软件二、开始安装1、双击运行软件&#xff08;适合自己的M芯片版或Intel芯片版&#xff09;&#xff0c;将其从左侧拖入右侧文件夹中&#xff0c;等待安装完毕2、应用程序显示软件图标&#xff0c;表示安装成功3、打开访达&#xff0c;点击【文…

MySQL进阶-索引-使用规则-最左前缀法则和范围查询

文章目录 1、最左前缀法则2、启动mysql3、查询tb_user4、查看tb_user的索引5、执行计划 profession 软件工程 and age31 and status 06、执行计划 profession 软件工程 and age317、执行计划 profession 软件工程8、执行计划 age31 and status 09、执行计划 status 010、执行…

前端实战:实现块级元素的拖拽与缩放功能

在现代网页开发中&#xff0c;用户交互是一个非常重要的部分。在这篇文章中&#xff0c;我们将详细介绍如何使用原生 JavaScript 实现块级元素的拖拽与缩放功能。具体来说&#xff0c;我们将实现以下功能&#xff1a; 点击并拖动 outer 元素&#xff0c;可以移动整个块。点击并…

利用LinkedHashMap实现一个LRU缓存

一、什么是 LRU LRU是 Least Recently Used 的缩写&#xff0c;即最近最少使用&#xff0c;是一种常用的页面置换算法&#xff0c;选择最近最久未使用的页面予以淘汰。 简单的说就是&#xff0c;对于一组数据&#xff0c;例如&#xff1a;int[] a {1,2,3,4,5,6}&#xff0c;…

Android Studio上传新项目到Gitee

一、在Gitee上创建仓库 首先需要再Gitee上创建仓库 1、在Gitee中新建仓库 2、输入仓库信息 3、生成仓库地址 创建成功会生成一个仓库地址&#xff0c;格式如下&#xff1a; https://gitee.com/test/compose_mvi_demo.git二、Android Studio 上传项目到Gitee 1、在Android …

MySQL数据库笔记(二)

第一章 单行函数 1.1 什么是函数 函数的作用是把我们经常使用的代码封装起来,需要的时候直接调用即可。这样既提高了代码效率,又提高了可维护性。在SQL中使用函数,极大地提高了用户对数据库的管理效率。 1.2 定义 操作数据对象。 接受参数返回一个结果。 只对一行进行…

使用PEFT库进行ChatGLM3-6B模型的LORA高效微调

PEFT库进行ChatGLM3-6B模型LORA高效微调 LORA微调ChatGLM3-6B模型安装相关库使用ChatGLM3-6B模型GPU显存占用准备数据集加载模型加载数据集数据处理数据集处理配置LoRA配置训练超参数开始训练保存LoRA模型模型推理从新加载合并模型使用微调后的模型 LORA微调ChatGLM3-6B模型 本…

【SpringSecurity】认证与鉴权框架SpringSecurity——授权

目录 权限系统的必要性常见的权限管理框架SpringSecurity授权基本流程准备脚本限制访问资源所需权限菜单实体类和Mapper封装权限信息封装认证/鉴权失败处理认证失败封装鉴权失败封装配置SpringSecurity 过滤器跨域处理接口添加鉴权hasAuthority/hasAnyAuthorityhasRole/​ hasA…

node mySql 实现数据的导入导出,以及导入批量插入的sql语句

node 实现导出, 在导出excel中包含图片&#xff08;附件&#xff09; node 实现导出, 在导出excel中包含图片&#xff08;附件&#xff09;-CSDN博客https://blog.csdn.net/snows_l/article/details/139999392?spm1001.2014.3001.5502 一、效果 如图&#xff1a; 二、导入 …

声场合成新方法:基于声波传播的框架

声场合成是指在房间内的麦克风阵列上&#xff0c;根据来自房间内其他位置的声源信号&#xff0c;合成每个麦克风的音频信号。它是评估语音/音频通信设备性能指标的关键任务&#xff0c;因为它是一种成本效益高的方法&#xff0c;用于数据生成以替代真实的数据收集&#xff0c;后…

elasticsearch的安装和配置

单节点安装与部署 我们通过docker进行安装 1.docker的安装 如果以及安装了docker就可以跳过这个步骤。 首先更新yum: yum update安装docker: yum install docker查看docker的版本&#xff1a; docker -v此时我们的docker就安装成功了。 2.创建网络 我们还需要部署kiban…

盲源信道分离—FastICA算法性能仿真

本案例中使用Matlab软件对FastICA算法的声音分离性能进行了仿真&#xff0c;分别对简单波形的混合信号、不同类型声音的混合信号、同一类型的混合信号这三种情况进行仿真&#xff0c;主要从分离信号的波形形状、串音误差两方面对分离性能进行衡量&#xff0c;仿真结果显示快速I…

可以一键生成热点营销视频的工具,建议收藏

在当今的商业环境中&#xff0c;热点营销已经成为了一种非常重要的营销策略。那么&#xff0c;什么是热点营销呢&#xff1f;又怎么做热点营销视频呢&#xff1f; 最近高考成绩慢慢公布了&#xff0c;领导让结合“高考成绩公布”这个热点&#xff0c;做一个关于企业或产品的营销…

3.任务的创建与删除

1.什么是任务&#xff1f; 任务可以理解为进程/线程&#xff0c;创建一个任务&#xff0c;就会在内存开辟一个空间。 任务通常都含有while(1)死循环 2.任务创建与删除相关的函数 3.CUBEMAX相关配置 编辑一个led1闪烁的任务