封装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实现 ...
随机推荐
- 2020 Web 全栈面经
2020 Web 全栈面经 1.简历 2. 技术 3. 项目 4. 架构 5. 沟通,协作 6.成长 7. 面试技巧 准备 电话确认,面试流程,五险一金缴纳情况 有无笔试,几轮,面试时间,答复时间 细 ...
- MobX All In One
MobX All In One Simple, scalable state management. https://mobx.js.org/README.html https://github.co ...
- live chat for website UX
live chat for website UX increase customer satisfaction using a live chat https://crisp.chat/en/live ...
- umi
umi https://github.com/umijs/umi https://umijs.org/zh/guide/ dva https://github.com/dvajs/dva https: ...
- C++ 中的智能指针-基础
简介 在现代 C++ 编程中,标准库包含了智能指针(Smart pointers). 智能指针用来确保程序不会出现内存和资源的泄漏,并且是"异常安全"(exception-safe ...
- 【转】ICP算法(Iterative Closest Point迭代最近点算法)
原文网址:https://www.cnblogs.com/sddai/p/6129437.html.转载主要方便随时可以查看,如有版权要求请及时联系. 最近在做点云匹配,需要用c++实现ICP算法,下 ...
- 19_MySQL表的内连接
本节所涉及的SQL语句: -- 表连接查询 -- 查询每名员工(员工名字,编号)的部门信息(部门编号,部门名称) SELECT e.empno,e.ename,d.dname FROM t_emp e ...
- 生产者和消费者问题(synchronized、Lock)
1.synchronized的生产者和消费者 synchronized是锁住对象 this.wait()释放了锁 并等待 this.notify()随机通知并唤醒同一个对象中的一个线程 this.no ...
- python进阶(4)文件操作
文件操作 文件操作主要包括对文件内容的读写操作,这些操作是通过文件对象实现的,通过文件对象可以读写文本文件和二进制文件 open(file, mode='r', buffering=-1, encod ...
- 【转】理解Serverless
理解Serverless No silver bullet. - The Mythical Man-Month 许多年前,我们开发的软件还是C/S(客户端/服务器)和MVC(模型-试图-控制器)的形式 ...