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

原文阅读

相关推荐
熊的猫28 分钟前
JS 中的类型 & 类型判断 & 类型转换
前端·javascript·vue.js·chrome·react.js·前端框架·node.js
瑶琴AI前端1 小时前
uniapp组件实现省市区三级联动选择
java·前端·uni-app
会发光的猪。1 小时前
如何在vscode中安装git详细新手教程
前端·ide·git·vscode
我要洋人死2 小时前
导航栏及下拉菜单的实现
前端·css·css3
科技探秘人2 小时前
Chrome与火狐哪个浏览器的隐私追踪功能更好
前端·chrome
科技探秘人2 小时前
Chrome与傲游浏览器性能与功能的深度对比
前端·chrome
JerryXZR2 小时前
前端开发中ES6的技术细节二
前端·javascript·es6
七星静香2 小时前
laravel chunkById 分块查询 使用时的问题
java·前端·laravel
q2498596933 小时前
前端预览word、excel、ppt
前端·word·excel
小华同学ai3 小时前
wflow-web:开源啦 ,高仿钉钉、飞书、企业微信的审批流程设计器,轻松打造属于你的工作流设计器
前端·钉钉·飞书