vue table列表组件_element table固定列

vue table列表组件_element table固定列最近接到一个新需求,一个表单组件, 要求横向和纵向两种模式,要求固定表头和首列。这里做个记录。 这样就比较清晰了。剩下的就是核心代码编写了。 接下来遇到的一个问题就是多级表头了。 仔细分析这个dom结构。其实他是分成三行来渲染的, 然后通过rowspan和colspan来实现的…

最近接到一个新需求,一个表单组件, 要求横向和纵向两种模式,要求固定表头和首列。这里做个记录。 首先呢, 当然是踩在巨人的肩膀上, 看看其他的开源库怎么实现的固定表头和首列,

一、结构分析

效果

vue table列表组件_element table固定列

拆分

vue table列表组件_element table固定列

代码

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部分,

vue table列表组件_element table固定列

这样就比较清晰了。剩下的就是核心代码编写了。

二、实现

接下来遇到的一个问题就是多级表头了。

vue table列表组件_element table固定列

仔细分析这个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分别是这个表头的顶级单元格

vue table列表组件_element table固定列
vue table列表组件_element table固定列

// 从树形整理成二维数组
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将这个数组变成一个二维数组、每一层的节点在一个数组内

vue table列表组件_element table固定列

通过这么整理过的数据就可以直接通过循环渲染出来了。

其他细节, 样式的调整

  • colgroup和col可以快速的格式化单元格,而col的个数就是这个table列的个数, 应该是每一个树的最终节点的和
    vue table列表组件_element table固定列
  • 出现纵向滚动条之后会影响到整体宽度, 导致横向混动thead和tbody不同步。产生错位, 如下图
    vue table列表组件_element table固定列

    解决办法是判断当纵向滚动条存在的时候, 在thead添加一个单元格, 宽度为滚动条的宽度

vue table列表组件_element table固定列

 // 获取滚动条宽度
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;
};
  • 在出现横向滚动条的时候, 左边绝对定位会覆盖一部分横向滚动条, 如下

    vue table列表组件_element table固定列

    所以也要特殊处理, 限制左边的tbody容器的高度减去一个滚动条的高度

  • 如果窗口宽度大于表格的理论宽度, 表格就会自动适应, 底部的tbody边框了。而左边绝对定位的宽度没变, 会导致错位, 所以要给table设置一个宽度, 这个宽度是可以通过列数*每列的宽计算出来的

  • 如果需要操作栏的话, 可以通过vue的作用域插槽来实现, 将当列的数据抛出去就好了

这样, 一个横向的固定表头首列就完成了, 实际上就是element table组建的劣化版。有时间再写一下纵向表单的处理, 相对来说要复杂一下。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/12875.html

(0)

相关推荐

  • 1.5.4 HDFS 客户端操作-hadoop「终于解决」

    1.5.4 HDFS 客户端操作-hadoop「终于解决」1.5.4 HDFS 客户端操作 1.5.4.1 Shell 命令行操作HDFS 基本语法 ​ bin/hadoop fs 具体命令 OR bin/hdfs dfs 具体命令 命令大全 [root@l

    2023-06-19
    77
  • redis 集群(文档整理)「建议收藏」

    redis 集群(文档整理)「建议收藏」Redis集群 &#183;Redis集群提供了一种运行Redis安装的方法,在该安装中,数据会在多个Redis节点之间自动分片。 Redis集群在分区期间还提供了一定程度的可用性,这实际上是

    2023-03-13
    91
  • metadata怎么打开_查看过分享是什么意思

    metadata怎么打开_查看过分享是什么意思作者:洪斌 爱可生南区负责人兼技术服务总监,MySQL ACE,擅长数据库架构规划、故障诊断、性能优化分析,实践经验丰富,帮助各行业客户解决 MySQL 技术问题,为金融、运营商、互联网等行业客户提…

    2023-03-13
    105
  • 云小课|MRS基础原理之Hudi介绍「终于解决」

    云小课|MRS基础原理之Hudi介绍「终于解决」阅识风云是华为云信息大咖,擅长将复杂信息多元化呈现,其出品的一张图(云图说)、深入浅出的博文(云小课)或短视频(云视厅)总有一款能让您快速上手华为云。更多精彩内容请单击此处。 摘要:Hudi是数据湖的

    2023-06-12
    98
  • Python Tkinter Radiobuttons: 界面选项的交互性控制

    Python Tkinter Radiobuttons: 界面选项的交互性控制Radiobuttons 是Tkinter库中的一个可用控件,用于创建多个互斥的选项。每个选项是一个圆形按钮,用户只能选择其中的一个选项。Radiobuttons控件非常有用,可以用来设计交互性很强的用户界面。

    2024-03-09
    31
  • html代码基础知识讲解

    html代码基础知识讲解</b> 粗体字 <strong>…>分割窗口 99彩|http://99caiw.com<frames

    2022-12-14
    100
  • 观察者模式(JavaScript实现)「建议收藏」

    观察者模式(JavaScript实现)「建议收藏」观察者模式中通常有两个模型,一个观察者(observer)和一个被观察者(Observed)。从字面意思上理解,即被观察者发生某些行为或者变化时,会通知观察者,观察者根据此行为或者变化做出处理。那么具体如何操作呢,接下来我们就用JavaScript代码实现一个下图👇所示的观察…

    2023-07-24
    77
  • Web应用安全如何防御或者检查漏洞?

    Web应用安全如何防御或者检查漏洞?     Web应用安全如何防御或者检查漏洞?这是大家一直关心的问题。随着计算机技术的发展,网络漏洞也变得越来越多样化了,你知道吗,每隔9 小时就会发布 1 个严重漏洞,并且有可能会进行远程代码执行…

    2022-12-20
    101

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注