使ElementUI的el-table表头自动吸顶,支持左右固定列

背景

在使用el-table的时候,在数据多的情况下滚动表格会看不到表头是什么,可以使用高度自适应,这是对表格高度的限制同时会出现滚动条,这样用户体验不好,所以考虑不设置高度通过表头吸顶来实现。

思路

网上也有一些解决方案写了一大堆代码。很麻烦。(os:我没成功过)

我研究了el-table的dom结构,发现其实只需要少量简单的计算去修改样式就可以达到效果。

主要还是使用CSS属性 position: sticky

注意

由于使用的是sticky,所以要保证祖先元素不能设置overflow:hidden这类的样式,否则不生效。

效果

实现

为了方便使用,把表头吸顶写成一个方法,最后在指令里调用即可。

  1. 吸顶高度确认

指令什么都不传默认吸顶高度为0,可以传递具体的吸顶高度值(数字),可以传递可以获取到dom的选择器名

javascript 复制代码
const stickyThead = (el, binging, vnode) => {
	let top = "0px";
    //如果是吸顶高度
    if (!isNaN(Number(binging.value))) {
    	top = binging.value + "px";
  	}
    //如果是选择器名
    if (typeof binging.value === "string") {
    	let rect = document.querySelector(binging.value)?.getBoundingClientRect();
    	top = rect ? rect.top + rect.height + "px" : "0px";
  	}
}
  1. 头部吸顶
javascript 复制代码
el.style.overflow = "visible";
const tHeader = el.querySelector(".el-table__header-wrapper");
tHeader.style.position = "sticky";
tHeader.style.top = top;
tHeader.style.zIndex = 10;

到这里基本上已经实现表头吸顶的功能了,但是如果出现固定列的话就不行。那么继续完善。

研究表格元素结构发现,没有固定列的头部在el-table__header-wrapper,而有固定列的头部会被额外拆分到el-table__fixed、el-table__fixed-right, 其实可以直接修改el-table__header-wrapper里面的th样式即可。

  1. 去除is-hidden

需要把th中的is-hidden这个类名删除,才会显示固定列的头

javascript 复制代码
const ths = tHeader.querySelectorAll("th.is-hidden");
ths.forEach((item) => {
	item.classList.remove("is-hidden");
});
  1. 固定列吸顶
javascript 复制代码
// 找到实例
const table = vnode.context.$children.find((item) => item.$el === el);
// 找到左边固定列的信息
const leftFixed = table.fixedColumns;
if (leftFixed && leftFixed.length) {
	let leftFixedWidth = 0;
	leftFixed.forEach((item) => {
		let itemW = item.width || item.realWidth || item.minWidth;
		const cell = tHeader.querySelector("th." + item.id);
		if (cell) {
			cell.style.position = "sticky";
			cell.style.left = leftFixedWidth + "px";
			cell.style.top = top;
			cell.style.zIndex = 10;
			leftFixedWidth += itemW;
		}
	});
}

// 找到右边固定列
const rightFixed = table.rightFixedColumns;
if (rightFixed && rightFixed.length) {
	let rightFixedWidth = 0;
	for (let i = rightFixed.length - 1; i >= 0; i--) {
		let itemW = rightFixed[i].width || rightFixed[i].realWidth || rightFixed[i].minWidth;
      const cell = tHeader.querySelector("th." + rightFixed[i].id);
      if (cell) {
        cell.style.position = "sticky";
        cell.style.right = rightFixedWidth + "px";
        cell.style.top = top;
        cell.style.zIndex = 10;
        rightFixedWidth += itemW;
      }
    }
  }
};

细节: 右边的固定列要倒着设置

  1. 指令调用时机
javascript 复制代码
var tableOb = null;
var domOb = null;
export default {
  inserted(el, binging, vnode) {
    //监听表格变化
    tableOb = new ResizeObserver(() => {
      stickyThead(el, binging, vnode);
    });
    tableOb.observe(el);

    // 监听目标dom变化
    if (typeof binging.value === "string") {
      let isDom = document.querySelector(binging.value);
      if (isDom) {
        domOb = new ResizeObserver(() => {
          stickyThead(el, binging, vnode);
        });
        domOb.observe(isDom);
      }
    }
  },
  unbind(el, binging, vnode) {
    tableOb && tableOb.unobserve(el);
    if (typeof binging.value === "string") {
      let isDom = document.querySelector(binging.value);
      if (isDom) {
        domOb && domOb.unobserve(el);
      }
    }
  },
};
  • 思考一:表格监听

表格插入到页面的时候要监听表格的变化,从而调用这个方法,这个监听是必要的,能够在表格变化的时候重新计算位置。(考虑左右位置的计算)

  • 思考二:目标元素监听

在使用目标元素来决定吸顶高度时,随着页面的变化可能目标元素的高度会变高,那就有必要重新调用这个方法,如果高度固定就不需要监听;或者目标元素的宽小于等于表格的宽度,这样页面变化会触发表格的监听同样不需要这个监听。所以这个监听不是必要的。主要关注点还是在stickyThead这个方法上,剩下的就是触发时机。(考虑吸顶的位置)

原文阅读

相关推荐
福兮说3 小时前
设计稿是 #4A7C6F,页面量出来是 #4B7C6F:HEX、HSL、透明度、canvas 来回转的七个坑
前端·javascript·css·canvas
郑州光合科技余经理4 小时前
海外版外卖加盟:总站与分站配送规则怎么分开管
java·开发语言·前端·后端·uni-app·php·ai编程
小呆呆6665 小时前
副业搞起来,小说,漫画,漫剧的成本优化思路
前端·后端·面试
Dovis(誓平步青云)5 小时前
浇水提醒刚弹出又消失,植物状态别只存一个百分比
开发语言·前端·javascript·pdf·ecmascript·电脑
码艺-Alimjan5 小时前
Vben Admin 新增维吾尔语 Vben-Modal的关键坑之一
前端·javascript·vue.js
可乐鸡翅yeah_6 小时前
hls.js 手动自定义 http 请求 loader,修改请求头实战
开发语言·前端·javascript·网络协议·http·ecmascript·m3u8在线
IT_陈寒6 小时前
Vite静态资源导入这个坑我帮你们踩过了
前端·人工智能·后端
广州华水科技6 小时前
大坝安全监测解决方案:单北斗GNSS形变监测系统应用与维护
前端
yivifu7 小时前
中文古籍电子书注释集成
前端·javascript·python·beautifulsoup·epub
默_笙8 小时前
🛴 从散件到整机:DeepAgents 与 Agent 身上预留的那些"插槽"(前置介绍)
前端·javascript