京东6.18大促主会场领京享红包更优惠

 找回密码
 立即注册

QQ登录

只需一步,快速开始

html原生table实现合并单元格以及合并表头的示例代码

2024-11-3 03:30| 发布者: 4d5a8576d| 查看: 21| 评论: 0

摘要: 目次媒介思路实现的功能表头分组设置主体代码高出的行数高出的列数实现效果图合并单元格以及单元格放组件设置主体代码以及单元格放组件高出的行数高出的列数实现效果图滚动条总结媒介 由于公司业务越来越复杂,有些
目次

媒介

由于公司业务越来越复杂,有些页面PC和app其实是一样的,我们肯定不想写两套代码,以是我们看看能不能写一个同时支持PC和app的table组件

思路

起首肯定想到的是原生table举行封装,由于我早就想这么干了,想通过原生的一些基础组件去封装成咱们可用的组件库。说搞就搞,先实现table的一些简单功能,由于公司用的js框架是vue,以是基于vue3去封装。

实现的功能

  • 表头分组
  • 合并单元格
  • 滚动条
  • 单元格放组件

表头分组

表头分组这个概念也是ant-design-vue中看来的,反正我的明确就是合并单元格,但是它叫表头分组,可能专业些,好吧,已经复制了它的叫法。
通过设置去天生分组的表头,起首要对原生table的一些设置要比较熟练,先容两个最重要的设置

  • rowspan 表格高出的行数
  • colspan 表格高出的列数

设置

copy了一份ant的较为复杂的结构,然后稍微改一了一下标识字段,方便我们本身组件使用

[code] const columns: columnsType[] = [ { prop: 'index', label: '', width: 3 }, { label: 'Other', children: [ { prop: 'age', label: 'Age', }, { label: 'Address', children: [ { label: 'Street', prop: 'street' }, { label: 'Block', children: [ { label: 'Building', prop: 'building', }, { label: 'Door No.', prop: 'number', }, ], }, ] } ] }, ][/code]

主体代码

[code] // 头部 <thead> <tr v-for="(row, index) in renderHeaderList" :key="index"> <th v-for="columnsItem in row" :key="columnsItem.prop" :rowspan="computedHeaderRowSpan(columnsItem)" :colspan="computedHeaderColSpan(columnsItem)" :class="`width-${columnsItem.width} height-${tableHeaderHeight} header-b`" > // 使用组件的原因是方便扩展其他业务需求 <headerCell :columnsItem="columnsItem"></headerCell> </th> </tr> </thead>[/code]

高出的行数

起首肉眼看到的肯定是表头高出了4行。但是我们也不能写死成4行,我们须要通过计算得到这个表头最终高出的几行。表头行数跨不跨行的判定依据是有无children。以是我这里是通过递归去扁平化这个数组,最终得到表格高出了几行。

[code] /** * @description 递归扁平化设置数组,得到渲染表头的数组以及高出的的行数 * @param columns children */ function handleRenderHeaderList(columns:columnsType[]) { // 用于记录深度 headerIndex.value += 1 if (renderHeaderList.value.length <= headerIndex.value) { renderHeaderList.value.push(columns) } else { renderHeaderList.value[headerIndex.value] = [...renderHeaderList.value[headerIndex.value],...columns] } // 用于记录是否重置深度 let isClearIndex = true columns.forEach((item: columnsType) => { // 判定是否还有子集 if (item.children && item.children.length > 0 ) { isClearIndex = false handleRenderHeaderList(item.children) } }); if(isClearIndex){ headerIndex.value = 0 } } /** * @description 单独rowspan的计算 * @param columnsItem 单元格的设置 * @return 单元格的列数 */ function computedHeaderRowSpan(columnsItem:columnsType){ if(!columnsItem.children){ return renderHeaderList.value.length } return 1 }[/code]

高出的列数

这个列数也是不固定的,也须要去通过收集对应的children里面的项数来统计,由于我们是无法确认这个children的深度的,以是我这边用深度遍历来处理子集的收集标题。由于用递归此时vue会报告诫,实际上我们也须要知道递归多了,内存就消耗的多,以是我们能不消递归就尽量不消递归。

[code] /** * @description 单独colSpan的计算 * @param columnsItem 单元格的设置 * @return 单元格的列数 */ function computedHeaderColSpan(columnsItem:columnsType){ if(!columnsItem.children){ return 1 } return flatColumnsItemChildren(columnsItem.children).length } /** * @description 深度遍历扁平化数组获取单元格所占的列数 * @param columnsItem 单元格的设置 * @return 返回扁平化后的数组 */ function flatColumnsItemChildren(columnsItem:columnsType[]){ // 深度遍历,扁平化数组 let node, list = [...columnsItem], nodes = [] while (node = list.shift()) { // 要过滤一下没有prop的,没有prop的列不参加最终的宽度计算 if(node.prop){ nodes.push(node) } node.children && list.unshift(...node.children) } return nodes // 递归会报告诫,占内存 // if(columnsItem.length === 0){ // return // } // columnsItem.forEach((item:columnsType)=>{ // if(item.children){ // flatColumnsItemChildren(item.children) // }else{ // flatChildrenList.value.push(item) // } // }) }[/code]

实现效果图

合并单元格以及单元格放组件

合并单元格稍微简单些,只须要把每个单元格的colspan和rowspan写成一个函数并且袒露出来就能处理

设置

[code] const columns: columnsType[] = [ { prop: 'monitor', label: '班次', customCell: (_?: rowType, index?: number, columns?: columnsType) => { if (index === 2 && columns?.prop === 'monitor') { return { colspan:3 }; } if (index === 0 && columns?.prop === 'monitor') { return { rowspan:2 }; } if (index === 1 && columns?.prop === 'monitor') { return { rowspan:0 }; } return {colspan:1,rowspan:1}; }, }, { prop: 'taHao', label: '塔号', customCell: (_?: rowType, index?: number, columns?: columnsType) => { if (index === 2 && columns?.prop === 'taHao') { return {colspan : 0}; } return {colspan:1}; }, }, { prop: 'materialNum', label: '投料量', customCell: (_?: rowType, index?: number, columns?: columnsType) => { if (index === 2 && columns?.prop === 'materialNum') { return {colspan : 0}; } return {colspan:1}; }, }, { prop: 'temperature', label: '沸腾罐温度', rowSpan: 2 }, { prop: 'steamPressure', label: '蒸汽压力' }, { prop: 'steamPressure1', label: '蒸汽压力2' }, { prop: 'oxygen', label: '真空度' }, { prop: 'productNum', label: '制品产量' }, { prop: 'operatorName', label: '操作人' }, { prop: 'operatorTime', label: '操作时间' }, ];[/code]

主体代码以及单元格放组件

[code] <tbody> <tr v-for="(item, index) in tableData" :key="index"> <template v-for="(headerItem, headerIndex) in renderDataList" :key="headerIndex" > <td v-if=" computedTdColspan(item, index, headerItem) !== 0 && computedTdRowspan(item, index, headerItem) !== 0 " align="center" :class="`height-${tableCellHeight} cell-b`" :colspan="computedTdColspan(item, index, headerItem)" :rowspan="computedTdRowspan(item, index, headerItem)" > // 动态组件提前写好组件去渲染对应的组件,此时的table单元格扩展性就变得非常强,不 仅可以做展示用,也可以放输入框,下拉选择器之类的组件。 <component :is="components[headerItem.type]" :ref="(el:unknown) => setComponentRef(el, headerItem.prop)" :form-item="headerItem" :value="item" ></component> </td> </template> </tr> </tbody>[/code]

高出的行数

每个单元格渲染的时候,袒露一个函数出去,此函数的返回值有rowspan以及colspan,如许能准确的知道渲染每个单元格时此单元格占位多少。

[code] /** * @description 计算单元格rowspan的占位 * @param item 单元格一行的值 * @param index 索引 * @param columns 当前的单元格设置 * @return colspan */ function computedTdRowspan(item: rowType, index: number, columns: columnsType): number|undefined { if (columns.customCell) { let rowspan: number| undefined = 1 if(columns.customCell(item, index, columns).rowspan ===0){ rowspan = 0 } if(columns.customCell(item, index, columns).rowspan){ rowspan = columns.customCell(item, index, columns).rowspan } return rowspan } return 1; }[/code]

高出的列数

每个单元格渲染的时候,袒露一个函数出去,此函数的返回值有rowspan以及colspan,如许能准确的知道渲染每个单元格时此单元格占位多少。

[code] /** * @description 计算单元格colspan的占位 * @param item 单元格一行的值 * @param index 索引 * @param columns 当前的单元格设置 * @return colspan */ function computedTdColspan(item: rowType, index: number, columns: columnsType): number|undefined { if (columns.customCell) { let colspan: number| undefined = 1 if(columns.customCell(item, index, columns).colspan ===0){ colspan = 0 } if(columns.customCell(item, index, columns).colspan){ colspan = columns.customCell(item, index, columns).colspan } return colspan } return 1; }[/code]

实现效果图

滚动条

table自身是相应式的,按照一定规则自动去分配宽度和高度的,假如不在table表面包裹一层元素的话,table会一直自顺应,没法带有滚动条,我们须要给外层元素设置一个宽度或者高度,然后table也设置一个固定的宽度或者是高度,如许内部的table就会在限定的宽度或者高度下具有滚动条。

总结

为了更好的在特定场景去控制table的高宽以及单元格的高宽,我们可以将他们的样式设定为动态的,我们可以通过设置去动态的改变他们的样式。然后就是处理一些无法确认层级的树形结构数据,我们也可以不通过递归去实现,节省内存。

到此这篇关于html原生table实现合并单元格以及合并表头的示例代码的文章就先容到这了,更多相关html table合并单元格及表头内容请搜刮脚本之家从前的文章或继续欣赏下面的相关文章,希望大家以后多多支持脚本之家!


来源:https://www.jb51.net/html5/878203.html
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
关闭

站长推荐上一条 /6 下一条

QQ|手机版|小黑屋|梦想之都-俊月星空 ( 粤ICP备18056059号 )|网站地图

GMT+8, 2025-7-2 02:57 , Processed in 0.036008 second(s), 18 queries .

Powered by Mxzdjyxk! X3.5

© 2001-2025 Discuz! Team.

返回顶部