大家好,我是考100分的小小码 ,祝大家学习进步,加薪顺利呀。今天说一说vue table列表组件_element table固定列,希望您对编程的造诣更进一步.
最近接到一个新需求,一个表单组件, 要求横向和纵向两种模式,要求固定表头和首列。这里做个记录。 首先呢, 当然是踩在巨人的肩膀上, 看看其他的开源库怎么实现的固定表头和首列,
一、结构分析
效果
拆分
代码
分析
其实, 整个表单被分成了三个部分, 每一种颜色是一个单独的表格块,拼接起来的, 每一个部分都是用一个容器包裹着一个table表单, 用于限制宽高和处理滚动
<div class="wrapper">
<table></table>
</div>
- 黄色部分, 只渲染了表头部分,外部容器
overflo:hidden
, - 绿色部分就是核心, 渲染了tbody部分, 外部容器
overflow: atuo
, 监听他的滚动条事件, 然后同步到固定表头和固定列的滚动条 - 蓝色部分其实包含了了一个thead和tbody, 然后设置宽度等于首列的宽,
overflow: hidden
然后绝对定位覆盖在右边的表单上面 - 在body部分横向滚动的时候, thead同步滚动, 在body垂直滚动的时候, 左边的tbody也同步滚动
这里我用了两个子组件tableHead和tableBody来分别渲染thead和tbody部分,
这样就比较清晰了。剩下的就是核心代码编写了。
二、实现
接下来遇到的一个问题就是多级表头了。
仔细分析这个dom结构。其实他是分成三行来渲染的, 然后通过rowspan和colspan来实现的合并单元格 所以我们需要通过算法, 将树形的表头数据摊开成一个二维数组, 然后每个数据节点都需要算出rowspan和colspan。
这里总结一下规律
- 每一个单元格的colsan应该是他全部子节点的总数,如果他不含子节点,则为1
- 每一个单元格的rowspan分两种情况, 如果他不含子节点, 就是最大层数-当前曾是 + 1, 如果包含子节点,则为1
丢代码
// 提取全部的列
const getAllColumns = (columns) => {
const result = [];
columns.forEach((column) => {
if (column.childs && column.childs.length) {
result.push(column);
result.push.apply(result, getAllColumns(column.childs));
// result.push(...getAllColumns(column.childs))
} else {
result.push(column);
}
});
return result;
}
这个函数的作用是将多个树形结构组成的数组摊平 A、B分别是这个表头的顶级单元格
// 从树形整理成二维数组
const convertToRows = (originColumns) => {
let maxLevel = 1;
// 递归的算出每一个子节点的层数, 和colspan
const traverse = (column, parent) => {
if (parent) {
column.level = parent.level + 1;
if (maxLevel < column.level) {
maxLevel = column.level;
}
}
if (column.childs && column.childs.length) {
let colSpan = 0;
column.childs.forEach((subColumn) => {
traverse(subColumn, column);
colSpan += subColumn.colSpan;
});
// 节点的colspan是子节点的和
column.colSpan = colSpan;
} else {
// 不存在则为一
column.colSpan = 1;
}
};
originColumns.forEach((column) => {
column.level = 1;
traverse(column);
});
const rows = [];
for (let i = 0; i < maxLevel; i++) {
rows.push([]);
}
// 转化成一维数组的数据,
// 注意, 在调用getAllColumns之前, 已经将每一个节点设置好了level
const allColumns = getAllColumns(originColumns);
// 转化成二维数组, 计算rowspan
allColumns.forEach((column) => {
if (!column.childs.length) {
column.rowSpan = maxLevel - column.level + 1;
} else {
column.rowSpan = 1;
}
rows[column.level - 1].push(column);
});
return rows;
}
这一步将根据level将这个数组变成一个二维数组、每一层的节点在一个数组内
通过这么整理过的数据就可以直接通过循环渲染出来了。
其他细节, 样式的调整
- colgroup和col可以快速的格式化单元格,而col的个数就是这个table列的个数, 应该是每一个树的最终节点的和
- 出现纵向滚动条之后会影响到整体宽度, 导致横向混动thead和tbody不同步。产生错位, 如下图
解决办法是判断当纵向滚动条存在的时候, 在thead添加一个单元格, 宽度为滚动条的宽度
// 获取滚动条宽度
export function getScrollbarWidth() {
if (Vue.prototype.$isServer) return 0;
if (scrollBarWidth !== undefined) return scrollBarWidth;
const outer = document.createElement('div');
outer.className = 'el-scrollbar__wrap';
outer.style.visibility = 'hidden';
outer.style.width = '100px';
outer.style.position = 'absolute';
outer.style.top = '-9999px';
document.body.appendChild(outer);
const widthNoScroll = outer.offsetWidth;
outer.style.overflow = 'scroll';
const inner = document.createElement('div');
inner.style.width = '100%';
outer.appendChild(inner);
const widthWithScroll = inner.offsetWidth;
outer.parentNode.removeChild(outer);
scrollBarWidth = widthNoScroll - widthWithScroll;
return scrollBarWidth;
};
-
在出现横向滚动条的时候, 左边绝对定位会覆盖一部分横向滚动条, 如下
所以也要特殊处理, 限制左边的tbody容器的高度减去一个滚动条的高度
-
如果窗口宽度大于表格的理论宽度, 表格就会自动适应, 底部的tbody边框了。而左边绝对定位的宽度没变, 会导致错位, 所以要给table设置一个宽度, 这个宽度是可以通过列数*每列的宽计算出来的
-
如果需要操作栏的话, 可以通过vue的作用域插槽来实现, 将当列的数据抛出去就好了
这样, 一个横向的固定表头首列就完成了, 实际上就是element table组建的劣化版。有时间再写一下纵向表单的处理, 相对来说要复杂一下。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/12875.html