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

2024-06-22 21:36

本文主要是介绍【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

这篇关于【low-ui-vue】实现原生可扩展动态表格组件的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1085480

相关文章

Vue3 的 shallowRef 和 shallowReactive:优化性能

大家对 Vue3 的 ref 和 reactive 都很熟悉,那么对 shallowRef 和 shallowReactive 是否了解呢? 在编程和数据结构中,“shallow”(浅层)通常指对数据结构的最外层进行操作,而不递归地处理其内部或嵌套的数据。这种处理方式关注的是数据结构的第一层属性或元素,而忽略更深层次的嵌套内容。 1. 浅层与深层的对比 1.1 浅层(Shallow) 定义

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

【 html+css 绚丽Loading 】000046 三才归元阵

前言:哈喽,大家好,今天给大家分享html+css 绚丽Loading!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 📚一、效果📚二、信息💡1.简介:💡2.外观描述:💡3.使用方式:💡4.战斗方式:💡5.提升:💡6.传说: 📚三、源代码,上代码,可以直接复制使用🎥效果🗂️目录✍️

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

动态规划---打家劫舍

题目: 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。 思路: 动态规划五部曲: 1.确定dp数组及含义 dp数组是一维数组,dp[i]代表