背景
在使用el-table
的時候葬毫,在數(shù)據(jù)多的情況下滾動表格會看不到表頭是什么,可以使用高度自適應(yīng)屡穗,這是對表格高度的限制同時會出現(xiàn)滾動條贴捡,這樣用戶體驗不好,所以考慮不設(shè)置高度通過表頭吸頂來實現(xiàn)村砂。
思路
網(wǎng)上也有一些解決方案寫了一大堆代碼栈暇。很麻煩。(os:我沒成功過)
我研究了el-table
的dom
結(jié)構(gòu)箍镜,發(fā)現(xiàn)其實只需要少量簡單的計算去修改樣式就可以達(dá)到效果源祈。
主要還是使用CSS
屬性position: sticky
注意
由于使用的是sticky
,所以要保證祖先元素不能設(shè)置overflow:hidden
這類的樣式色迂,否則不生效香缺。
效果
使用
import {tableSticky} from 'lp-vue'
Vue.directive('tableSticky', tableSticky)
實現(xiàn)
為了方便使用,把表頭吸頂寫成一個方法歇僧,最后在指令里調(diào)用即可图张。
- 吸頂高度確認(rèn)
指令什么都不傳默認(rèn)吸頂高度為0锋拖,可以傳遞具體的吸頂高度值(數(shù)字),可以傳遞可以獲取到
dom
的選擇器名
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";
}
}
- 頭部吸頂
el.style.overflow = "visible";
const tHeader = el.querySelector(".el-table__header-wrapper");
tHeader.style.position = "sticky";
tHeader.style.top = top;
tHeader.style.zIndex = 10;
到這里基本上已經(jīng)實現(xiàn)表頭吸頂?shù)墓δ芰嘶雎郑侨绻霈F(xiàn)固定列的話就不行兽埃。那么繼續(xù)完善。
研究表格元素結(jié)構(gòu)發(fā)現(xiàn)适袜,沒有固定列的頭部在el-table__header-wrapper
柄错,而有固定列的頭部會被額外拆分到el-table__fixed
、el-table__fixed-right
苦酱, 其實可以直接修改el-table__header-wrapper
里面的th
樣式即可售貌。
- 去除
is-hidden
需要把th中的is-hidden這個類名刪除,才會顯示固定列的頭
const ths = tHeader.querySelectorAll("th.is-hidden");
ths.forEach((item) => {
item.classList.remove("is-hidden");
});
- 固定列吸頂
// 找到實例
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;
}
}
}
};
細(xì)節(jié): 右邊的固定列要倒著設(shè)置
- 指令調(diào)用時機
var tableOb = null;
var domOb = null;
export default {
inserted(el, binging, vnode) {
//監(jiān)聽表格變化
tableOb = new ResizeObserver(() => {
stickyThead(el, binging, vnode);
});
tableOb.observe(el);
// 監(jiān)聽目標(biāo)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);
}
}
},
};
- 思考一:表格監(jiān)聽
表格插入到頁面的時候要監(jiān)聽表格的變化疫萤,從而調(diào)用這個方法颂跨,這個監(jiān)聽是必要的,能夠在表格變化的時候重新計算位置扯饶。(考慮左右位置的計算)
- 思考二:目標(biāo)元素監(jiān)聽
在使用目標(biāo)元素來決定吸頂高度時恒削,隨著頁面的變化可能目標(biāo)元素的高度會變高,那就有必要重新調(diào)用這個方法尾序,如果高度固定就不需要監(jiān)聽蔓同;或者目標(biāo)元素的寬小于等于表格的寬度,這樣頁面變化會觸發(fā)表格的監(jiān)聽同樣不需要這個監(jiān)聽蹲诀。所以這個監(jiān)聽不是必要的。主要關(guān)注點還是在stickyThead
這個方法上弃揽,剩下的就是觸發(fā)時機脯爪。(考慮吸頂?shù)奈恢茫?/p>