因爲項目表格的列數不少,因此table
必然會出現橫向滾動條。然而若是頁面自己內容較多,出現縱向的滾動條,就會出現須要先滾動到表格底部(table
的橫向滾動條默認在容器底部),才能進行左右的拉動,這給部分用戶帶來了不便。css
table
的height
來規避掉縱向滾動條的出現,從而保證橫向滾動條始終位於視口底部。缺點就是在一些小屏幕,例如筆記本上,會致使表格可展示的條數過少。el-table
的可訪問性很優秀,能夠經過← →
快捷鍵來橫向滾動。或者按住鼠標中鍵滑動也能夠。缺點就是很多用戶不知道或者不習慣這樣的操做方式。我的認爲也能夠作引導,但要考慮設計友好的交互和用戶的接受程度。(ps: 手動狗頭.jpg)先看一下最終效果,以下圖所示:html
一句話歸納就是當表格容器底部不在可視區域範圍內時,橫向滾動條固定在視口底部的位置。vue
本身實現一個橫向滾動條固定在視口底部,同步這個滾動條和el-table
的scroll
事件。當el-table
原生的橫向滾動條出如今可視區域範圍內時,隱藏自定義滾動條。node
在el-table
內部生成一個自定義橫向滾動條,當el-table
原生的橫向滾動條沒出如今可視區域範圍內時,將自定義滾動條調整到視口底部位置,反之隱藏該自定義滾動條。git
我採用了思路二。因爲用的是Vue
,又涉及到操做Dom
,故而把這個功能封裝成了一個指令的形式,使用起來在el-table
上添加指令便可。github
核心代碼以下:express
//自定義滾動條
import PerfectScrollbar from 'perfect-scrollbar';
//對應的css
import "perfect-scrollbar/css/perfect-scrollbar.css";
const updateScrollBar = (el) => {
const railX = el.querySelector(".ps__rail-x");
const _tbody = el;
//若是table內部還有滾動條的話須要加上_tbody.scrollTop
const _top = window.innerHeight - _tbody.getBoundingClientRect().top - railX.clientHeight;
railX.style.top = `${_top}px`;
railX.style.opacity = "1";
railX.style.display = "block";
}
const el_scrollBar = (el) => {
if (el._ps_ instanceof PerfectScrollbar) {
el._ps_.update();
} else {
el._ps_ = new PerfectScrollbar(el, {
suppressScrollX: false,
suppressScrollY: true //y方向禁止
});
// setTimeout(() => {
// el._ps_.update();
// }, 17);
}
};
let isScrolling = false;
let _scrollHander = null;
let _resizeHander = null;
const directive = {
inserted(el) {
el = el.querySelector(".el-table__body-wrapper");
if (!el) {
return console.warn("未發現className爲el-table__body-wrapper的dom");
}
const rules = ["fixed", "absolute", "relative"];
if (!rules.includes(window.getComputedStyle(el, null).position)) {
console.error(`perfect-scrollbar所在的容器的position屬性必須是如下之一:${rules.join("、")}`)
}
el_scrollBar(el);
updateScrollBar(el);
//註冊scroll和resize事件
_scrollHander = () => {
if (!isScrolling) {
window.requestAnimationFrame(() => {
updateScrollBar(el);
isScrolling = false;
});
}
isScrolling = true;
};
_resizeHander = () => {
updateScrollBar(el)
}
document.addEventListener("scroll", _scrollHander)
window.addEventListener("resize", _resizeHander)
},
componentUpdated(el, binding, vnode) {
const {
expression
} = binding;
el = el.querySelector(".el-table__body-wrapper");
if (!el) {
return console.warn("未發現className爲el-table__body-wrapper的dom");
}
const handler = () => vnode.context[expression].apply();
vnode.context.$nextTick(
() => {
try {
el_scrollBar(el);
updateScrollBar(el);
if (expression) {
handler()
}
} catch (error) {
console.error(error);
}
}
)
},
unbind() {
document.removeEventListener("scroll", _scrollHander)
window.removeEventListener("resize", _resizeHander)
}
}
export default directive;
複製代碼
在inserted
的時候初始化自定義滾動條,採用的是PerfectScrollbar
。PerfectScrollbar
實際生成的橫向滾動條<div class='ps__rail-x'></div>
,經過動態設置滾動條的top
值來維持滾動條在視口底部。segmentfault
一個簡單的幾何公式:bash
//若是table內部還有滾動條的話須要加上_tbody.scrollTop
//視口的高度 - tbody基於視口的top值 - 橫向滾動條容器的高度
const _top = window.innerHeight - _tbody.getBoundingClientRect().top - railX.clientHeight;
複製代碼
在el-table
組件更新後從新初始化滾動條,scroll
和resize
事件觸發時更新滾動條位置便可。app
若是表格有固定列,因爲el-table
的固定列設置了z-index:4
,因此須要給滾動條容器設置大一點的z-index
。
.ps__rail-x {
display: block;
z-index: 99; /*大於fixed table 的z-index*/
}
複製代碼
在表格自己的橫向滾動條出如今可視區域內後,因爲自定義滾動條的位置已經處於表格下方,一部分在原生滾動條所在區域,原生滾動條會覆蓋自定義滾動條;一部分溢出在表格外部(el-table
設置了overflow:hidden
);兩部分都不可見,所以未對自定義滾動條作隱藏。
若是須要隱藏滾動條,能夠監聽表格內最後一個tr
的可見性。
在實現的過程當中發現,PerfectScrollbar
的縱向滾動條會影響帶有固定列的el-table
的滾動同步(固定列是基於多個table實現的),就把y方向上的滾動禁止掉了。但這樣會致使el-table
縱向滾動失效。
考慮到通常不會有雙重滾動條,即body內有滾動,table內也有滾動,因此就沒去深究解決方案。
若是真的出現雙重滾動條的狀況,能夠考慮使用上文中的思路一去實現。