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

背景

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

思路

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

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

主要还是使用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__fixedel-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这个方法上,剩下的就是触发时机。(考虑吸顶的位置)

原文阅读

相关推荐
m0_7482309419 分钟前
Redis 通用命令
前端·redis·bootstrap
YaHuiLiang1 小时前
一切的根本都是前端“娱乐圈化”
前端·javascript·代码规范
ObjectX前端实验室2 小时前
个人网站开发记录-引流公众号 & 谷歌分析 & 谷歌广告 & GTM
前端·程序员·开源
CL_IN2 小时前
企业数据集成:实现高效调拨出库自动化
java·前端·自动化
浪九天3 小时前
Vue 不同大版本与 Node.js 版本匹配的详细参数
前端·vue.js·node.js
qianmoQ4 小时前
第五章:工程化实践 - 第三节 - Tailwind CSS 大型项目最佳实践
前端·css
椰果uu4 小时前
前端八股万文总结——JS+ES6
前端·javascript·es6
微wx笑5 小时前
chrome扩展程序如何实现国际化
前端·chrome
~废弃回忆 �༄5 小时前
CSS中伪类选择器
前端·javascript·css·css中伪类选择器
CUIYD_19895 小时前
Chrome 浏览器(版本号49之后)‌解决跨域问题
前端·chrome