封装Vue纵向表头左右结构的table表格
我们前端开发人员在使用表格的过程中,大概率碰到的都是表格头部在表格的最上边,然后呈一行展示,紧接着就是表格的每一行的每一个单元格来展示具体内容的场景,很少会遇到表格的头部呈纵向一行展示,也就是说表格的头部在左边,具体的内容在右边(也可以说是左右结构)这种使用场景,而且有时候的场景可能会是纵向表头有两列或多列。
遇到这样的需求或者说使用场景,你也不能说人家产品提的需求不合理,毕竟使用场景不同。我不知道咱们同行的前端大佬是用啥牛逼格拉斯的技术来实现这样的需求的,反正我以前基本都是直接上一个表格,然后各种tr、td的往上堆,如果需要展示的多了,最后会发现整个页面上基本全是各种tr、td的标签,Level Low就不说了,关键是看着闹心、烦心外加恶心。
最近想着说再遇到这样的需求,可不能再各种tr、td往上堆了,恰好近期的需求开发上也有这样的使用场景,索性就动动脑筋自己封装一个吧,以后用起来也方便,也能提高开发效率,界面看起来也能清爽不少。
一开始搞的时候,确实没头绪,很懵圈。上网搜了一把,想着说看看能不能找点灵感,或者说有好的例子能借鉴一下,结果一圈下来,发现就算是有人搞过这样的封装,也是感觉词不达意,说好的封装呢?有人基于elementUI就实现了一列纵向表头的封装,有人基于索引实现了两列纵向表头的封装,但代码中出现的各种数字令人费解,不利于扩展。
算了,还是自己想办法吧。不有句话说的好嘛:“人的脑洞有多大,就能实现多牛逼的需求。”于是,对着设计稿上这样的表格,我是左看右看,上看下看,后来突然想到我们经常使用的表单组件,大概率不就是左右结构嘛,基于这个我又想到曾经在封装Vue Element的form表单组件的时候还使用过分段的思想,现在把这个分段的思想用在这里不正好吗?
办法总比困难多,这句老俗语总结的真是太TMD的完全正确了!
照例先上一张效果图:

1、封装的纵向表头表格组件Table.vue
<template>
<table class="portait-table" border="1" cellspacing="0" cellpadding="0">
<tr v-for="(row, i) in columns" :key="i">
<template v-for="x in row">
<TD :config="x" :data="data" />
</template>
</tr>
</table>
</template>
<script>
import * as Components from '@/components/table/cell/components'
import { chunk } from '@/utils'
import { noop } from '@/common/constant'
export default {
props: {config: Object},
data() {
const {headers, data, rowSize = 2} = this.config || {}
return {
headers,
data,
rowSize,
};
},
computed: {
columns: ({headers, rowSize}) => chunk(headers, rowSize)
},
components: {
TD: {
functional: true,
props: {config: Object, data: Object},
render: (h, {props: {config, data}}) => {
let {type = 'Default', label, prop} = config, value = data[prop], isEmpty = value === '' || value === undefined || value === null, children = noop
if(label && isEmpty) children = h(Components.Default, {props: {value: '-'}})
else children = h(Components[type], {props: {value, data, ...config}})
return [h('td', label), h('td', [children])]
}
}
},
mounted(){
const {columns} = this, last = columns[columns.length - 1], lastTwo = columns[columns.length - 2]
for(let i = 0; i < (lastTwo.length - last.length); i++){
this.headers.push({prop: '', label: ''})
}
},
}
</script>
<style lang="scss" scoped>
.portait-table{
border-collapse: collapse;
border: none;
width:100%;
td {
border: 1px solid #F3F3F3;
height: 40px;
padding-left: 10px;
color:#333;
&:nth-child(odd){
background: #EAEAEA;
color: #454545;
}
}
}
</style>
对于以上组件中的代码,需要做一些以下说明。
2、分段工具的实现chunk
export const chunk = (arr, size) => {
if(!arr.length || size < 1) return [];
let list = [], index = 0, resIndex = 0, len = arr.length;
while (index < len) {
list[resIndex++] = arr.slice(index, index += size);
}
return list;
}
数组被分段后的效果,你可以自己打印出来看看就明白了。
3、封装的组件中引入了一些其他的组件是干嘛使的呢?比如:
import * as Components from '@/components/table/cell/components'
引入这些组件,主要是为了对一些特殊的字段值进行特殊的处理,比如金额千分位、时间戳格式化、枚举(映射)等,这些组件的具体代码和介绍在我的这篇博文封装Vue Element的table表格组件中有具体的描述,您可以摆驾过去上上眼。
4、代码中的render函数,这里也不再赘述,我之前的博文中都有介绍,你也可以自己去看vue的API或查阅其他资料。
5、在封装的组件的mounted生命周期里有这样一段代码:
const {columns} = this, last = columns[columns.length - 1], lastTwo = columns[columns.length - 2]
for(let i = 0; i < (lastTwo.length - last.length); i++){
this.headers.push({prop: '', label: ''})
}
这段代码是干嘛滴的呢?我们都知道,像这样的纵向表头左右结构展示的表格,不管你分了几列表头(只有一列表头的除外)展示,都有可能在表格的最后一行出现不完整的情况,也就是说可能会在整个表格的右下角出现空缺的情况,如下图:

这种类似表格残缺不全的情况当然是不被允许的,mounted生命周期中的那段代码就是用来补这个缺的。其原理就是拿分段后的最后一个数组长度与倒数第二个数组长度进行比较,如果两者不相等,则最后一个数组长度比倒数第二个数组长度少了几个,就在headers数组的最后push几个属性值是空的的对象,最后再利用计算属性去重新分段(组件中的计算属性会被执行两次,第一次是初始分段,第二次是补缺后的再次分段),就达到了本文开头展示的补缺后的效果图。
其实,代码中真正补缺的原理可能与我描述的实现不太一样,比如代码中并没有拿分段后的最后一个数组长度与倒数第二个数组长度进行比较,而是用了一个for循环就搞定了,因为for循环也有自己的判断嘛,但是原理真的差不离。
6、至于那个noop,它其实就是定义了一个能返回空对象的函数export const noop = () => {},它在封装中的作用就是用来初始化函数。还有那个rowSize,是用来设置分成几段的,默认是2段。
7、封装时用到了computed计算属性,这个属性想必大家已经很熟了,这里再多说一句吧:计算属性的key的值是一个函数,其参数是Vue的实例化this对象。为啥这里要强调这一点呢,是因为知道了这一点,我们就可以在其函数的参数中直接解构this了,比如:
computed: {
columns: ({headers, rowSize}) => chunk(headers, rowSize)
},
而我们平时常用的写法是:
computed: {
columns(){
const {headers, rowSize} = this
return chunk(headers, rowSize)
}
},
两厢对比,哪种写法更优雅、性能更高呢?当然是前者了。
8、使用封装后的表格Table组件
<template>
<Table :config="config" />
</template>
<script>
import Table from '@/components/Table'
export default {
components: {
Table
},
data(){
return {
config: {
headers: [
{prop: 'ruleName', label: '规则名称'},
{prop: 'money', label: '执行金额', type: 'Currency'},
{prop: 'fileName', label: '附件名称'},
{prop: 'ruleRiskLevel', label: '预警颜色'},
{prop: 'monitorResult', label: '监控结果', type: 'Enum', Enum: {name: 'monitor'}},
{prop: 'productCode', label: '产品系列'},
{prop: 'date', label: '执行时间', type: 'Date', format: 'yyyy-MM-dd'},
],
rowSize: 2,
data: {
ruleName: '股权质押',
money: 3256898,
fileName: '',
ruleRiskLevel: '红色',
monitorResult: '00',
productCode: '事业部',
date: new Date().getTime(),
}
}
}
},
}
</script>
本文到此,基本就实现了纵向表头的table表格封装,想展示几列表头,就把rowSize设置成几就可以了,非常方便。
封装Vue纵向表头左右结构的table表格的更多相关文章
- Vue + Element-ui实现后台管理系统(5)---封装一个Form表单组件和Table表格组件
封装一个Form表单组件和Table组件 有关后台管理系统之前写过四遍博客,看这篇之前最好先看下这四篇博客.另外这里只展示关键部分代码,项目代码放在github上: mall-manage-syste ...
- 封装Vue Element的table表格组件
上周分享了几篇关于React组件封装方面的博文,这周就来分享几篇关于Vue组件封装方面的博文,也好让大家能更好地了解React和Vue在组件封装方面的区别. 在封装Vue组件时,我依旧会交叉使用函数式 ...
- 封装Vue Element的可编辑table表格组件
前一段时间,有博友在我那篇封装Vue Element的table表格组件的博文下边留言说有没有那种"表格行内编辑"的封装组件,我当时说我没有封装过这样的组件,因为一直以来在实际开发 ...
- element-ui的table表格控件表头与内容列不对齐问题
原文链接:点我 element-ui的table表格控件表头与内容列不对齐问题 解决方法:将以下样式代码添加到index.html.或app.vue中(必须是入口文件,起全局作用!)body .el- ...
- asp.net table表格表头及列固定实现
http://blog.csdn.net/zdw_wym/article/details/48630337 在开发中常会遇到table表格中列特别多,下拉后,表头就看不见了,水平滚动后,第1.2列就看 ...
- 封装Vue Element的form表单组件
前两天封装了一个基于vue和Element的table表格组件,阅读的人还是很多的,看来大家都是很认同组件化.高复用这种开发模式的,毕竟开发效率高,代码优雅,逼格高嘛.虽然这两天我的心情很糟糕,就像& ...
- element-ul二次封装table表格
在项目中el的表格使用的地方太多了,若不进行封装,使用的时候页面会显得非常的冗余且难以维护,有时表格样式还不能做到一致:今天分享一个在工作中封装的表格 由于大多代码都在页面有介绍,就不在外面解释了 一 ...
- 5种做法实现table表格中的斜线表头效果
table表格,这个东西大家肯定都不陌生,代码中我们时常都能碰到,那么给table加一个斜线的表头有时是很有必要的,但是到底该怎么实现这种效果呢? 我总结了以下几种方法: 1.最最最简单的做法 直接去 ...
- js 实现table表格拖拽和点击表头升降序排序
js 实现table表格拖拽和点击表头升降序排序,写的比较乱,用的时候可以把其中的一些模块函数提取出来 样式,由于是可拖拽表格,所以样式 table tr th{cursor:move;} js实现 ...
随机推荐
- nodemon all in one
nodemon all in one https://nodemon.io/ https://github.com/remy/nodemon#nodemon https://www.npmjs.com ...
- Web 网站安全测试 & 渗透测试
Web 网站安全测试 & 渗透测试 Penetration Testing learning path 建一个测试环境来进行渗透测试 安装 Kali Linux -渗透测试操作系统 在虚拟机中 ...
- element ui 停止维护了
️♂️ element ui 停止维护了 最近看到有人说 element ui 已经停止维护了,还有点不相信; 不过到 github 验证一下,好像是真的呀 4 个月,没有任何更新了 https:/ ...
- Flutter 将TextField平滑过渡到Text
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends State ...
- Spring中的@Enable注解
本文转载自SpringBoot中神奇的@Enable注解? 导语 在SpringBoot开发过程,我们经常会遇到@Enable开始的好多注解,比如@EnableEurekaServer.@Enable ...
- Spring Boot和Thymeleaf整合,结合JPA实现分页效果
在项目里,我需要做一个Spring Boot结合Thymeleaf前端模版,结合JPA实现分页的演示效果.做的时候发现有些问题,也查了现有网上的不少文档,发现能全栈实现的不多,所以这里我就把我的做法, ...
- 如何用Eggjs从零开始开发一个项目(2)
在上一篇文章,我们已经使用Sequelize连接上了数据库,并能进行简单的数据库操作,在此基础上,我们试着来开发一个完整的项目.这篇文章我们从用户的注册.登录着手,试着开发用户模块的相关的代码. 用户 ...
- Docker-compose编排微服务顺序启动
一.概述 docker-compose可以方便组合多个 docker 容器服务, 但是, 当容器服务之间存在依赖关系时, docker-compose 并不能保证服务的启动顺序.docker-comp ...
- 学习java的第二天
Java第二天 标识符 标识符开头只能以字母和_开头 严格区分大小写 不能以关键词命名 变量 变量是什么:就是可以变化的量 Java是一种强类型语言,定义变量必须声明后才能使用 Java变量是程序中最 ...
- C语言相关的基础字符串函数
C语言中没有专门的字符串类型,所以就用字符数组和字符指针形式表示 1 char arr[]="abcdef"; //字符数组表示的字符串 2 char*arr="abce ...